From 3a5603966467a878e5b305517598589590cb8b10 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 21 Sep 2010 15:20:10 +0100 Subject: Skeleton code for symbian native socket engine Taken the unix native socket engine, and converted each call from the posix version to the symbian version. There are many TODOs as this is quite incomplete. Reviewed-By: Markus Goetz --- src/network/socket/qnativesocketengine_p.h | 9 + src/network/socket/qnativesocketengine_symbian.cpp | 756 +++++++++++++++++++++ src/network/socket/socket.pri | 4 +- 3 files changed, 768 insertions(+), 1 deletion(-) create mode 100644 src/network/socket/qnativesocketengine_symbian.cpp diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h index 9baacf0..72ebd9f 100644 --- a/src/network/socket/qnativesocketengine_p.h +++ b/src/network/socket/qnativesocketengine_p.h @@ -63,6 +63,7 @@ #ifdef Q_OS_SYMBIAN #include #include +#include #endif QT_BEGIN_NAMESPACE @@ -196,6 +197,11 @@ public: ~QNativeSocketEnginePrivate(); int socketDescriptor; +#ifdef Q_OS_SYMBIAN + mutable RSocket nativeSocket; + RSocketServ socketServer; //TODO: shared ref + RConnection connection; //TODO: shared ref +#endif QSocketNotifier *readNotifier, *writeNotifier, *exceptNotifier; @@ -233,6 +239,9 @@ public: UnknownSocketErrorString = -1 }; +#ifdef Q_OS_SYMBIAN + void setError(TInt symbianError); +#endif void setError(QAbstractSocket::SocketError error, ErrorString errorString) const; // native functions diff --git a/src/network/socket/qnativesocketengine_symbian.cpp b/src/network/socket/qnativesocketengine_symbian.cpp new file mode 100644 index 0000000..f2aeee9 --- /dev/null +++ b/src/network/socket/qnativesocketengine_symbian.cpp @@ -0,0 +1,756 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +//#define QNATIVESOCKETENGINE_DEBUG +#include "qnativesocketengine_p.h" +#include "private/qnet_unix_p.h" +#include "qiodevice.h" +#include "qhostaddress.h" +#include "qelapsedtimer.h" +#include "qvarlengtharray.h" +#include +#include +#ifndef QT_NO_IPV6IFNAME +#include +#endif + +#define QNATIVESOCKETENGINE_DEBUG + +#if defined QNATIVESOCKETENGINE_DEBUG +#include +#include +#endif + +QT_BEGIN_NAMESPACE + +#if defined QNATIVESOCKETENGINE_DEBUG + +/* + Returns a human readable representation of the first \a len + characters in \a data. +*/ +static QByteArray qt_prettyDebug(const char *data, int len, int maxSize) +{ + if (!data) return "(null)"; + QByteArray out; + for (int i = 0; i < len; ++i) { + char c = data[i]; + if (isprint(c)) { + out += c; + } else switch (c) { + case '\n': out += "\\n"; break; + case '\r': out += "\\r"; break; + case '\t': out += "\\t"; break; + default: + QString tmp; + tmp.sprintf("\\%o", c); + out += tmp.toLatin1(); + } + } + + if (len < maxSize) + out += "..."; + + return out; +} +#endif + +static void qt_ignore_sigpipe() +{ +#ifndef Q_NO_POSIX_SIGNALS + // Set to ignore SIGPIPE once only. + static QBasicAtomicInt atom = Q_BASIC_ATOMIC_INITIALIZER(0); + if (atom.testAndSetRelaxed(0, 1)) { + struct sigaction noaction; + memset(&noaction, 0, sizeof(noaction)); + noaction.sa_handler = SIG_IGN; + ::sigaction(SIGPIPE, &noaction, 0); + } +#else + // Posix signals are not supported by the underlying platform + // so we don't need to ignore sigpipe signal explicitly +#endif +} + +/* + Extracts the port and address from a sockaddr, and stores them in + \a port and \a addr if they are non-null. +*/ +static inline void qt_socket_getPortAndAddress(const qt_sockaddr *s, quint16 *port, QHostAddress *addr) +{ +#if !defined(QT_NO_IPV6) + if (s->a.sa_family == AF_INET6) { + Q_IPV6ADDR tmp; + memcpy(&tmp, &s->a6.sin6_addr, sizeof(tmp)); + if (addr) { + QHostAddress tmpAddress; + tmpAddress.setAddress(tmp); + *addr = tmpAddress; +#ifndef QT_NO_IPV6IFNAME + char scopeid[IFNAMSIZ]; + if (::if_indextoname(s->a6.sin6_scope_id, scopeid)) { + addr->setScopeId(QLatin1String(scopeid)); + } else +#endif + addr->setScopeId(QString::number(s->a6.sin6_scope_id)); + } + if (port) + *port = ntohs(s->a6.sin6_port); + return; + } +#endif + if (port) + *port = ntohs(s->a4.sin_port); + if (addr) { + QHostAddress tmpAddress; + tmpAddress.setAddress(ntohl(s->a4.sin_addr.s_addr)); + *addr = tmpAddress; + } +} + +static inline void qt_socket_getPortAndAddress(const TInetAddr& a, quint16 *port, QHostAddress *addr) +{ +#if !defined(QT_NO_IPV6) + if (a.Family() == KAfInet6) { + Q_IPV6ADDR tmp; + memcpy(&tmp, a.Ip6Address().u.iAddr8, sizeof(tmp)); + if (addr) { + QHostAddress tmpAddress; + tmpAddress.setAddress(tmp); + *addr = tmpAddress; +#ifndef QT_NO_IPV6IFNAME + char scopeid[IFNAMSIZ]; + //TODO: rather than using posix api, the symbian way is + //to use GetOpt with TSoInetIfQuery and KSoInetIfQueryByIndex + //which means this should be in a member function to have access to the nativeSocket + if (::if_indextoname(a.Scope(), scopeid)) { + addr->setScopeId(QLatin1String(scopeid)); + } else +#endif + addr->setScopeId(QString::number(a.Scope())); + } + if (port) + *port = a.Port(); + return; + } +#endif + if (port) + *port = a.Port(); + if (addr) { + QHostAddress tmpAddress; + tmpAddress.setAddress(a.Address()); //TODO: byte order ok? + *addr = tmpAddress; + } +} +/*! \internal + + Creates and returns a new socket descriptor of type \a socketType + and \a socketProtocol. Returns -1 on failure. +*/ +bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType, + QAbstractSocket::NetworkLayerProtocol socketProtocol) +{ +#ifndef QT_NO_IPV6 + TUint family = (socketProtocol == QAbstractSocket::IPv6Protocol) ? KAfInet6 : KAfInet; +#else + Q_UNUSED(socketProtocol); + TUint family = KAfInet; +#endif + TUint type = (socketType == QAbstractSocket::UdpSocket) ? KSockDatagram : KSockStream; + TUint protocol = (socketType == QAbstractSocket::UdpSocket) ? KProtocolInetUdp : KProtocolInetTcp; + TInt err = nativeSocket.Open(socketServer, family, type, protocol, connection); + + if (err != KErrNone) { + switch (err) { + case KErrNotSupported: + case KErrNotFound: + setError(QAbstractSocket::UnsupportedSocketOperationError, + ProtocolUnsupportedErrorString); + break; + case KErrNoMemory: + setError(QAbstractSocket::SocketResourceError, ResourceErrorString); + break; + case KErrPermissionDenied: + setError(QAbstractSocket::SocketAccessError, AccessErrorString); + break; + default: + break; + } + + return false; + } + + socketDescriptor = nativeSocket.SubSessionHandle(); //TODO + return true; +} + +/* + Returns the value of the socket option \a opt. +*/ +int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) const +{ + Q_Q(const QNativeSocketEngine); + if (!q->isValid()) + return -1; + + TUint n; + TUint level = KSOLSocket; // default + + switch (opt) { + case QNativeSocketEngine::ReceiveBufferSocketOption: + n = KSORecvBuf; + break; + case QNativeSocketEngine::SendBufferSocketOption: + n = KSOSendBuf; + break; + case QNativeSocketEngine::NonBlockingSocketOption: + n = KSONonBlockingIO; + break; + case QNativeSocketEngine::BroadcastSocketOption: + n = SO_BROADCAST; //TODO + break; + case QNativeSocketEngine::AddressReusable: + n = SO_REUSEADDR; //TODO + break; + case QNativeSocketEngine::BindExclusively: + return true; + case QNativeSocketEngine::ReceiveOutOfBandData: + n = SO_OOBINLINE; //TODO + break; + case QNativeSocketEngine::LowDelayOption: + level = KSolInetTcp; + n = KSoTcpNoDelay; + break; + case QNativeSocketEngine::KeepAliveOption: + level = KSolInetTcp; + n = KSoTcpKeepAlive; + break; + default: + return -1; + } + + int v = -1; + //GetOpt() is non const + TInt err = nativeSocket.GetOpt(n, level, v); + if (!err) + return v; + + return -1; +} + + +/* + Sets the socket option \a opt to \a v. +*/ +bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt, int v) +{ + Q_Q(QNativeSocketEngine); + if (!q->isValid()) + return false; + + int n = 0; + int level = SOL_SOCKET; // default + + switch (opt) { + case QNativeSocketEngine::ReceiveBufferSocketOption: + n = KSORecvBuf; + break; + case QNativeSocketEngine::SendBufferSocketOption: + n = KSOSendBuf; + break; + case QNativeSocketEngine::BroadcastSocketOption: + n = SO_BROADCAST; //TODO + break; + case QNativeSocketEngine::NonBlockingSocketOption: + n = KSONonBlockingIO; + break; + case QNativeSocketEngine::AddressReusable: + n = SO_REUSEADDR; //TODO + break; + case QNativeSocketEngine::BindExclusively: + return true; + case QNativeSocketEngine::ReceiveOutOfBandData: + n = SO_OOBINLINE; //TODO + break; + case QNativeSocketEngine::LowDelayOption: + level = KSolInetTcp; + n = KSoTcpNoDelay; + break; + case QNativeSocketEngine::KeepAliveOption: + level = KSolInetTcp; + n = KSoTcpKeepAlive; + break; + } + + return (KErrNone == nativeSocket.SetOpt(n, level, v)); +} + +static TInetAddr qt_QHostAddressToTInetAddr(const QHostAddress &addr) +{ + TInetAddr nativeAddr; +#if !defined(QT_NO_IPV6) + if (addr.protocol() == QAbstractSocket::IPv6Protocol) { +#ifndef QT_NO_IPV6IFNAME + nativeAddr.SetScope(::if_nametoindex(addr.scopeId().toLatin1().data())); //TODO - if_nametoindex +#else + nativeAddr.SetScope(addr.scopeId().toInt()); +#endif + Q_IPV6ADDR ip6 = addr.toIPv6Address(); + TIp6Addr v6addr; + memcpy(v6addr.u.iAddr8, ip6.c, 16); + nativeAddr.SetAddress(v6addr); + } else +#endif + if (addr.protocol() == QAbstractSocket::IPv4Protocol) { + nativeAddr.SetAddress(addr.toIPv4Address()); + } else { + qWarning("unsupported network protocol (%d)", addr.protocol()); + } + return nativeAddr; +} + +bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16 port) +{ +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug("QNativeSocketEnginePrivate::nativeConnect() : %d ", socketDescriptor); +#endif + + TInetAddr nativeAddr = qt_QHostAddressToTInetAddr(addr); + nativeAddr.SetPort(port); + //TODO: async connect with active object - from here to end of function is a mess + TRequestStatus status; + nativeSocket.Connect(nativeAddr, status); + User::WaitForRequest(status); + TInt err = status.Int(); + if (err) { + switch (err) { + case KErrCouldNotConnect: + setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString); + socketState = QAbstractSocket::UnconnectedState; + break; + case KErrTimedOut: + setError(QAbstractSocket::NetworkError, ConnectionTimeOutErrorString); + break; + case KErrHostUnreach: + setError(QAbstractSocket::NetworkError, HostUnreachableErrorString); + socketState = QAbstractSocket::UnconnectedState; + break; + case KErrNetUnreach: + setError(QAbstractSocket::NetworkError, NetworkUnreachableErrorString); + socketState = QAbstractSocket::UnconnectedState; + break; + case KErrInUse: + setError(QAbstractSocket::NetworkError, AddressInuseErrorString); + break; + case KErrPermissionDenied: + setError(QAbstractSocket::SocketAccessError, AccessErrorString); + socketState = QAbstractSocket::UnconnectedState; + break; + case KErrNotSupported: + case KErrBadDescriptor: + socketState = QAbstractSocket::UnconnectedState; + default: + break; + } + + if (socketState != QAbstractSocket::ConnectedState) { +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEnginePrivate::nativeConnect(%s, %i) == false (%s)", + addr.toString().toLatin1().constData(), port, + socketState == QAbstractSocket::ConnectingState + ? "Connection in progress" : socketErrorString.toLatin1().constData()); +#endif + return false; + } + } + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEnginePrivate::nativeConnect(%s, %i) == true", + addr.toString().toLatin1().constData(), port); +#endif + + socketState = QAbstractSocket::ConnectedState; + return true; +} + +bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, quint16 port) +{ + TInetAddr nativeAddr = qt_QHostAddressToTInetAddr(address); + nativeAddr.SetPort(port); + + TInt err = nativeSocket.Bind(nativeAddr); + + if (err) { + switch(errno) { + case KErrInUse: + setError(QAbstractSocket::AddressInUseError, AddressInuseErrorString); + break; + case KErrPermissionDenied: + setError(QAbstractSocket::SocketAccessError, AddressProtectedErrorString); + break; + case KErrNotSupported: + setError(QAbstractSocket::UnsupportedSocketOperationError, OperationUnsupportedErrorString); + break; + default: + break; + } + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEnginePrivate::nativeBind(%s, %i) == false (%s)", + address.toString().toLatin1().constData(), port, socketErrorString.toLatin1().constData()); +#endif + + return false; + } + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEnginePrivate::nativeBind(%s, %i) == true", + address.toString().toLatin1().constData(), port); +#endif + socketState = QAbstractSocket::BoundState; + return true; +} + +bool QNativeSocketEnginePrivate::nativeListen(int backlog) +{ + TInt err = nativeSocket.Listen(backlog); + if (err) { + switch (errno) { + case KErrInUse: + setError(QAbstractSocket::AddressInUseError, + PortInuseErrorString); + break; + default: + break; + } + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEnginePrivate::nativeListen(%i) == false (%s)", + backlog, socketErrorString.toLatin1().constData()); +#endif + return false; + } + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEnginePrivate::nativeListen(%i) == true", backlog); +#endif + + socketState = QAbstractSocket::ListeningState; + return true; +} + +int QNativeSocketEnginePrivate::nativeAccept() +{ + RSocket blankSocket; + //TODO: this is unbelievably broken, needs to be properly async + blankSocket.Open(socketServer); + TRequestStatus status; + nativeSocket.Accept(blankSocket, status); + User::WaitForRequest(status); + if(status.Int()) { + qWarning("QNativeSocketEnginePrivate::nativeAccept() - error %d", status.Int()); + return 0; + } + + return blankSocket.SubSessionHandle(); +} + +qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const +{ + int nbytes = 0; + qint64 available = 0; + TInt err = nativeSocket.GetOpt(KSOReadBytesPending, KSOLSocket, nbytes); + if(err) + return 0; + available = (qint64) nbytes; + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEnginePrivate::nativeBytesAvailable() == %lli", available); +#endif + return available; +} + +bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const +{ + int nbytes; + TInt err = nativeSocket.GetOpt(KSOReadBytesPending,KSOLSocket, nbytes); + return err == KErrNone && nbytes > 0; + //TODO: this is pretty horrible too... +} + +qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const +{ + int nbytes; + TInt err = nativeSocket.GetOpt(KSOReadBytesPending,KSOLSocket, nbytes); + return qint64(nbytes-28); //TODO: why -28 (open C version had this)? +} + +qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxSize, + QHostAddress *address, quint16 *port) +{ + TPtr8 buffer((TUint8*)data, (int)maxSize); + TInetAddr addr; + TRequestStatus status; //TODO: OMG sync receive! + nativeSocket.RecvFrom(buffer, addr, 0, status); + User::WaitForRequest(status); + + if (status.Int()) { + setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString); + } else if (port || address) { + qt_socket_getPortAndAddress(addr, port, address); + } + +#if defined (QNATIVESOCKETENGINE_DEBUG) + int len = buffer.Length(); + qDebug("QNativeSocketEnginePrivate::nativeReceiveDatagram(%p \"%s\", %lli, %s, %i) == %lli", + data, qt_prettyDebug(data, qMin(len, ssize_t(16)), len).data(), maxSize, + address ? address->toString().toLatin1().constData() : "(nil)", + port ? *port : 0, (qint64) len); +#endif + + if (status.Int()) + return -1; + return qint64(buffer.Length()); +} + +qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 len, + const QHostAddress &host, quint16 port) +{ + TPtrC8 buffer((TUint8*)data, (int)len); + TInetAddr addr = qt_QHostAddressToTInetAddr(host); + TSockXfrLength sentBytes; + addr.SetPort(port); + TRequestStatus status; //TODO: OMG sync send! + nativeSocket.SendTo(buffer, addr, 0, status, sentBytes); + User::WaitForRequest(status); + TInt err = status.Int(); + + if (err) { + switch (err) { + case KErrTooBig: + setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString); + break; + default: + setError(QAbstractSocket::NetworkError, SendDatagramErrorString); + } + } + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEngine::sendDatagram(%p \"%s\", %lli, \"%s\", %i) == %lli", data, + qt_prettyDebug(data, qMin(len, 16), len).data(), len, host.toString().toLatin1().constData(), + port, (qint64) sentBytes()); +#endif + + return qint64(sentBytes()); +} + +bool QNativeSocketEnginePrivate::fetchConnectionParameters() +{ + localPort = 0; + localAddress.clear(); + peerPort = 0; + peerAddress.clear(); + + if (socketDescriptor == -1) + return false; + + //TODO: work out how to initialise nativeSocket from socketDescriptor + + // Determine local address + TSockAddr addr; + nativeSocket.LocalName(addr); + qt_socket_getPortAndAddress(addr, &localPort, &localAddress); + + // Determine protocol family + switch (addr.Family()) { + case KAfInet: + socketProtocol = QAbstractSocket::IPv4Protocol; + break; +#if !defined (QT_NO_IPV6) + case KAfInet6: + socketProtocol = QAbstractSocket::IPv6Protocol; + break; +#endif + default: + socketProtocol = QAbstractSocket::UnknownNetworkLayerProtocol; + break; + } + + // Determine the remote address + nativeSocket.RemoteName(addr); + qt_socket_getPortAndAddress(addr, &peerPort, &peerAddress); + + // Determine the socket type (UDP/TCP) + TProtocolDesc protocol; + TInt err = nativeSocket.Info(protocol); + if (err) { + QAbstractSocket::UnknownSocketType; + } else { + switch (protocol.iProtocol) { + case KProtocolInetTcp: + socketType = QAbstractSocket::TcpSocket; + break; + case KProtocolInetUdp: + socketType = QAbstractSocket::UdpSocket; + break; + default: + socketType = QAbstractSocket::UnknownSocketType; + break; + } + } +#if defined (QNATIVESOCKETENGINE_DEBUG) + QString socketProtocolStr = "UnknownProtocol"; + if (socketProtocol == QAbstractSocket::IPv4Protocol) socketProtocolStr = "IPv4Protocol"; + else if (socketProtocol == QAbstractSocket::IPv6Protocol) socketProtocolStr = "IPv6Protocol"; + + QString socketTypeStr = "UnknownSocketType"; + if (socketType == QAbstractSocket::TcpSocket) socketTypeStr = "TcpSocket"; + else if (socketType == QAbstractSocket::UdpSocket) socketTypeStr = "UdpSocket"; + + qDebug("QNativeSocketEnginePrivate::fetchConnectionParameters() local == %s:%i," + " peer == %s:%i, socket == %s - %s", + localAddress.toString().toLatin1().constData(), localPort, + peerAddress.toString().toLatin1().constData(), peerPort,socketTypeStr.toLatin1().constData(), + socketProtocolStr.toLatin1().constData()); +#endif + return true; +} + +void QNativeSocketEnginePrivate::nativeClose() +{ +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEngine::nativeClose()"); +#endif + + //TODO: call nativeSocket.Shutdown(EImmediate) in some cases? + nativeSocket.Close(); +} + +qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len) +{ + Q_Q(QNativeSocketEngine); + TPtrC8 buffer((TUint8*)data, (int)len); + TSockXfrLength sentBytes; + TRequestStatus status; //TODO: OMG sync send! + nativeSocket.Send(buffer, 0, status, sentBytes); + User::WaitForRequest(status); + TInt err = status.Int(); + + if (err) { + switch (err) { + case KErrDisconnected: + sentBytes = -1; + setError(QAbstractSocket::RemoteHostClosedError, RemoteHostClosedErrorString); + q->close(); + break; + case KErrTooBig: + setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString); + break; + case KErrWouldBlock: + sentBytes = 0; + default: + setError(QAbstractSocket::NetworkError, SendDatagramErrorString); + } + } + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEnginePrivate::nativeWrite(%p \"%s\", %llu) == %i", + data, qt_prettyDebug(data, qMin((int) len, 16), + (int) len).data(), len, (int) sentBytes()); +#endif + + return qint64(sentBytes()); +} +/* +*/ +qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize) +{ + Q_Q(QNativeSocketEngine); + if (!q->isValid()) { + qWarning("QNativeSocketEngine::nativeRead: Invalid socket"); + return -1; + } + + TPtr8 buffer((TUint8*)data, (int)maxSize); + TSockXfrLength received = 0; + TRequestStatus status; //TODO: OMG sync receive! + nativeSocket.RecvOneOrMore(buffer, 0, status, received); + User::WaitForRequest(status); + TInt err = status.Int(); + int r = received(); + + if (err) { + switch(err) { + case KErrWouldBlock: + // No data was available for reading + r = -2; + break; + case KErrDisconnected: + r = 0; + break; + default: + r = -1; + //error string is now set in read(), not here in nativeRead() + break; + } + } + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEnginePrivate::nativeRead(%p \"%s\", %llu) == %i", + data, qt_prettyDebug(data, qMin(r, ssize_t(16)), r).data(), + maxSize, r); +#endif + + return qint64(r); +} + +int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const +{ +//TODO: implement +} + +int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool checkWrite, + bool *selectForRead, bool *selectForWrite) const +{ + //TODO: implement +} + +QT_END_NAMESPACE diff --git a/src/network/socket/socket.pri b/src/network/socket/socket.pri index 2bafe13..f2262fe 100644 --- a/src/network/socket/socket.pri +++ b/src/network/socket/socket.pri @@ -25,7 +25,9 @@ SOURCES += socket/qabstractsocketengine.cpp \ socket/qlocalsocket.cpp \ socket/qlocalserver.cpp -unix:SOURCES += socket/qnativesocketengine_unix.cpp \ +unix:!symbian:SOURCES += socket/qnativesocketengine_unix.cpp +symbian:SOURCES += socket/qnativesocketengine_symbian.cpp +unix:SOURCES += \ socket/qlocalsocket_unix.cpp \ socket/qlocalserver_unix.cpp unix:HEADERS += \ -- cgit v0.12 From 5c7c12602f10be7625ee38efb31e1a8b5cb66c5b Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 21 Sep 2010 17:42:14 +0100 Subject: Prototype socket manager To enable passing socket handles around as integers, need a two way mapping with RSocket. It's in corelib because of QSocketNotifier. This is also a convenient place to host the global RSocketServ session. Reviewed-By: Markus Goetz --- src/corelib/io/io.pri | 2 +- src/corelib/kernel/qcore_symbian_p.cpp | 72 ++++++++++++++++++++++++++++++++++ src/corelib/kernel/qcore_symbian_p.h | 67 +++++++++++++++++++++++++++++++ 3 files changed, 140 insertions(+), 1 deletion(-) diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri index cfb40bc..6cf55e7 100644 --- a/src/corelib/io/io.pri +++ b/src/corelib/io/io.pri @@ -95,6 +95,6 @@ win32 { SOURCES += io/qfilesystemwatcher_symbian.cpp HEADERS += io/qfilesystemwatcher_symbian_p.h INCLUDEPATH += $$MW_LAYER_SYSTEMINCLUDE - LIBS += -lplatformenv + LIBS += -lplatformenv -lesock } } diff --git a/src/corelib/kernel/qcore_symbian_p.cpp b/src/corelib/kernel/qcore_symbian_p.cpp index df1c1ef..29996a4 100644 --- a/src/corelib/kernel/qcore_symbian_p.cpp +++ b/src/corelib/kernel/qcore_symbian_p.cpp @@ -210,4 +210,76 @@ Q_CORE_EXPORT RFs& qt_s60GetRFs() return qt_s60_RFsSession()->GetRFs(); } +QSymbianSocketManager::QSymbianSocketManager() : + iNextSocket(0) +{ + qt_symbian_throwIfError(iSocketServ.Connect()); + qt_symbian_throwIfError(iSocketServ.ShareAuto()); +} + +QSymbianSocketManager::~QSymbianSocketManager() +{ + iSocketServ.Close(); + if(!socketMap.isEmpty()) { + qWarning("leaked %d sockets on exit", socketMap.count()); + } +} + +RSocketServ& QSymbianSocketManager::getSocketServer() { + return iSocketServ; +} + +int QSymbianSocketManager::addSocket(RSocket* sock) { + QMutexLocker l(&iMutex); + Q_ASSERT(!socketMap.contains(sock)); + if(socketMap.contains(sock)) + return socketMap.value(sock); + // allocate socket number + int guard = 0; + while(reverseSocketMap.contains(iNextSocket)) { + iNextSocket++; + iNextSocket %= max_sockets; + guard++; + if(guard > max_sockets) + return -1; + } + int id = iNextSocket; + + socketMap[sock] = id; + reverseSocketMap[id] = sock; + return id + socket_offset; +} + +bool QSymbianSocketManager::removeSocket(RSocket* sock) { + QMutexLocker l(&iMutex); + if(!socketMap.contains(sock)) + return false; + int id = socketMap.value(sock); + socketMap.remove(sock); + reverseSocketMap.remove(id); + return true; +} + +int QSymbianSocketManager::lookupSocket(RSocket* sock) const { + QMutexLocker l(&iMutex); + if(!socketMap.contains(sock)) + return -1; + int id = socketMap.value(sock); + return id + socket_offset; +} + +RSocket* QSymbianSocketManager::lookupSocket(int fd) const { + QMutexLocker l(&iMutex); + int id = fd + socket_offset; + if(!reverseSocketMap.contains(id)) + return 0; + return reverseSocketMap.value(id); +} + +Q_GLOBAL_STATIC(QSymbianSocketManager, qt_symbianSocketManager); + +QSymbianSocketManager& QSymbianSocketManager::instance() +{ + return *(qt_symbianSocketManager()); +} QT_END_NAMESPACE diff --git a/src/corelib/kernel/qcore_symbian_p.h b/src/corelib/kernel/qcore_symbian_p.h index 4a515ce..b6cba6e 100644 --- a/src/corelib/kernel/qcore_symbian_p.h +++ b/src/corelib/kernel/qcore_symbian_p.h @@ -55,10 +55,12 @@ #include #include +#include #include #include #include #include +#include #define QT_LSTRING2(x) L##x #define QT_LSTRING(x) QT_LSTRING2(x) @@ -154,10 +156,75 @@ enum S60PluginFuncOrdinals Q_CORE_EXPORT TLibraryFunction qt_resolveS60PluginFunc(int ordinal); Q_CORE_EXPORT RFs& qt_s60GetRFs(); +Q_CORE_EXPORT RSocketServ& qt_symbianGetSocketServer(); // Defined in qlocale_symbian.cpp. Q_CORE_EXPORT QByteArray qt_symbianLocaleName(int code); +/*! + \internal + This class exists in QtCore for the benefit of QSocketNotifier, which uses integer + file descriptors in its public API. + So we need a way to map between int and RSocket. + Additionally, it is used to host the global RSocketServ session +*/ +class Q_CORE_EXPORT QSymbianSocketManager +{ +public: + QSymbianSocketManager(); + ~QSymbianSocketManager(); + + /*! + \internal + \return handle to the socket server + */ + RSocketServ& getSocketServer(); + /*! + \internal + Adds a symbian socket to the global map + \param an open socket + \return pseudo file descriptor, -1 if out of resources + */ + int addSocket(RSocket *sock); + /*! + \internal + Removes a symbian socket from the global map + \param an open socket + \return true if the socket was in the map + */ + bool removeSocket(RSocket *sock); + /*! + \internal + Get pseudo file descriptor for a socket + \param an open socket + \return integer handle, or -1 if not in map + */ + int lookupSocket(RSocket *sock) const; + /*! + \internal + Get socket for a pseudo file descriptor + \param an open socket fd + \return socket handle or NULL if not in map + */ + RSocket *lookupSocket(int fd) const; + + /*! + \internal + Gets a reference to the singleton socket manager + */ + static QSymbianSocketManager& instance(); +private: + int allocateSocket(); + + const static int max_sockets = 0x20000; //covers all TCP and UDP ports, probably run out of memory first + const static int socket_offset = 0x40000000; //hacky way of separating sockets from file descriptors + int iNextSocket; + QHash socketMap; + QHash reverseSocketMap; + mutable QMutex iMutex; + RSocketServ iSocketServ; +}; + QT_END_NAMESPACE QT_END_HEADER -- cgit v0.12 From 9470dfb8b116cde0d08670d05ded530bad264c6c Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Wed, 22 Sep 2010 12:04:01 +0100 Subject: Address some of the easier TODOs in native socket engine Reviewed-By: Markus Goetz --- src/network/socket/qnativesocketengine_p.h | 4 + src/network/socket/qnativesocketengine_symbian.cpp | 187 +++++++++++---------- 2 files changed, 105 insertions(+), 86 deletions(-) diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h index 72ebd9f..ceecfeb 100644 --- a/src/network/socket/qnativesocketengine_p.h +++ b/src/network/socket/qnativesocketengine_p.h @@ -64,6 +64,7 @@ #include #include #include +#include #endif QT_BEGIN_NAMESPACE @@ -201,6 +202,7 @@ public: mutable RSocket nativeSocket; RSocketServ socketServer; //TODO: shared ref RConnection connection; //TODO: shared ref + mutable RTimer selectTimer; #endif QSocketNotifier *readNotifier, *writeNotifier, *exceptNotifier; @@ -240,6 +242,8 @@ public: }; #ifdef Q_OS_SYMBIAN + void getPortAndAddress(const TInetAddr& a, quint16 *port, QHostAddress *addr); + void setPortAndAddress(TInetAddr& nativeAddr, quint16 port, const QHostAddress &addr); void setError(TInt symbianError); #endif void setError(QAbstractSocket::SocketError error, ErrorString errorString) const; diff --git a/src/network/socket/qnativesocketengine_symbian.cpp b/src/network/socket/qnativesocketengine_symbian.cpp index f2aeee9..788e58a 100644 --- a/src/network/socket/qnativesocketengine_symbian.cpp +++ b/src/network/socket/qnativesocketengine_symbian.cpp @@ -48,6 +48,7 @@ #include "qvarlengtharray.h" #include #include +#include #ifndef QT_NO_IPV6IFNAME #include #endif @@ -93,60 +94,7 @@ static QByteArray qt_prettyDebug(const char *data, int len, int maxSize) } #endif -static void qt_ignore_sigpipe() -{ -#ifndef Q_NO_POSIX_SIGNALS - // Set to ignore SIGPIPE once only. - static QBasicAtomicInt atom = Q_BASIC_ATOMIC_INITIALIZER(0); - if (atom.testAndSetRelaxed(0, 1)) { - struct sigaction noaction; - memset(&noaction, 0, sizeof(noaction)); - noaction.sa_handler = SIG_IGN; - ::sigaction(SIGPIPE, &noaction, 0); - } -#else - // Posix signals are not supported by the underlying platform - // so we don't need to ignore sigpipe signal explicitly -#endif -} - -/* - Extracts the port and address from a sockaddr, and stores them in - \a port and \a addr if they are non-null. -*/ -static inline void qt_socket_getPortAndAddress(const qt_sockaddr *s, quint16 *port, QHostAddress *addr) -{ -#if !defined(QT_NO_IPV6) - if (s->a.sa_family == AF_INET6) { - Q_IPV6ADDR tmp; - memcpy(&tmp, &s->a6.sin6_addr, sizeof(tmp)); - if (addr) { - QHostAddress tmpAddress; - tmpAddress.setAddress(tmp); - *addr = tmpAddress; -#ifndef QT_NO_IPV6IFNAME - char scopeid[IFNAMSIZ]; - if (::if_indextoname(s->a6.sin6_scope_id, scopeid)) { - addr->setScopeId(QLatin1String(scopeid)); - } else -#endif - addr->setScopeId(QString::number(s->a6.sin6_scope_id)); - } - if (port) - *port = ntohs(s->a6.sin6_port); - return; - } -#endif - if (port) - *port = ntohs(s->a4.sin_port); - if (addr) { - QHostAddress tmpAddress; - tmpAddress.setAddress(ntohl(s->a4.sin_addr.s_addr)); - *addr = tmpAddress; - } -} - -static inline void qt_socket_getPortAndAddress(const TInetAddr& a, quint16 *port, QHostAddress *addr) +void QNativeSocketEnginePrivate::getPortAndAddress(const TInetAddr& a, quint16 *port, QHostAddress *addr) { #if !defined(QT_NO_IPV6) if (a.Family() == KAfInet6) { @@ -157,13 +105,12 @@ static inline void qt_socket_getPortAndAddress(const TInetAddr& a, quint16 *port tmpAddress.setAddress(tmp); *addr = tmpAddress; #ifndef QT_NO_IPV6IFNAME - char scopeid[IFNAMSIZ]; - //TODO: rather than using posix api, the symbian way is - //to use GetOpt with TSoInetIfQuery and KSoInetIfQueryByIndex - //which means this should be in a member function to have access to the nativeSocket - if (::if_indextoname(a.Scope(), scopeid)) { - addr->setScopeId(QLatin1String(scopeid)); - } else + TPckgBuf query; + query().iSrcAddr = a; + TInt err = nativeSocket.GetOpt(KSoInetIfQueryBySrcAddr, KSolInetIfQuery, query); + if(!err) + addr->setScopeId(qt_TDesC2QString(query().iName)); + else #endif addr->setScopeId(QString::number(a.Scope())); } @@ -176,7 +123,7 @@ static inline void qt_socket_getPortAndAddress(const TInetAddr& a, quint16 *port *port = a.Port(); if (addr) { QHostAddress tmpAddress; - tmpAddress.setAddress(a.Address()); //TODO: byte order ok? + tmpAddress.setAddress(a.Address()); *addr = tmpAddress; } } @@ -218,7 +165,7 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc return false; } - socketDescriptor = nativeSocket.SubSessionHandle(); //TODO + socketDescriptor = QSymbianSocketManager::instance().addSocket(&nativeSocket); return true; } @@ -245,15 +192,16 @@ int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) co n = KSONonBlockingIO; break; case QNativeSocketEngine::BroadcastSocketOption: - n = SO_BROADCAST; //TODO - break; + return true; //symbian doesn't support or require this option case QNativeSocketEngine::AddressReusable: - n = SO_REUSEADDR; //TODO + level = KSolInetIp; + n = KSoReuseAddr; break; case QNativeSocketEngine::BindExclusively: return true; case QNativeSocketEngine::ReceiveOutOfBandData: - n = SO_OOBINLINE; //TODO + level = KSolInetTcp; + n = KSoTcpOobInline; break; case QNativeSocketEngine::LowDelayOption: level = KSolInetTcp; @@ -297,18 +245,19 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt n = KSOSendBuf; break; case QNativeSocketEngine::BroadcastSocketOption: - n = SO_BROADCAST; //TODO - break; + return true; case QNativeSocketEngine::NonBlockingSocketOption: n = KSONonBlockingIO; break; case QNativeSocketEngine::AddressReusable: - n = SO_REUSEADDR; //TODO + level = KSolInetIp; + n = KSoReuseAddr; break; case QNativeSocketEngine::BindExclusively: return true; case QNativeSocketEngine::ReceiveOutOfBandData: - n = SO_OOBINLINE; //TODO + level = KSolInetTcp; + n = KSoTcpOobInline; break; case QNativeSocketEngine::LowDelayOption: level = KSolInetTcp; @@ -323,13 +272,19 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt return (KErrNone == nativeSocket.SetOpt(n, level, v)); } -static TInetAddr qt_QHostAddressToTInetAddr(const QHostAddress &addr) +void QNativeSocketEnginePrivate::setPortAndAddress(TInetAddr& nativeAddr, quint16 port, const QHostAddress &addr) { - TInetAddr nativeAddr; + nativeAddr.SetPort(port); #if !defined(QT_NO_IPV6) if (addr.protocol() == QAbstractSocket::IPv6Protocol) { #ifndef QT_NO_IPV6IFNAME - nativeAddr.SetScope(::if_nametoindex(addr.scopeId().toLatin1().data())); //TODO - if_nametoindex + TPckgBuf query; + query().iName = qt_QString2TPtrC(addr.scopeId()); + TInt err = nativeSocket.GetOpt(KSoInetIfQueryByName, KSolInetIfQuery, query); + if(!err) + nativeAddr.SetScope(query().iIndex); + else + nativeAddr.SetScope(0); #else nativeAddr.SetScope(addr.scopeId().toInt()); #endif @@ -344,7 +299,6 @@ static TInetAddr qt_QHostAddressToTInetAddr(const QHostAddress &addr) } else { qWarning("unsupported network protocol (%d)", addr.protocol()); } - return nativeAddr; } bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16 port) @@ -353,8 +307,8 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16 qDebug("QNativeSocketEnginePrivate::nativeConnect() : %d ", socketDescriptor); #endif - TInetAddr nativeAddr = qt_QHostAddressToTInetAddr(addr); - nativeAddr.SetPort(port); + TInetAddr nativeAddr; + setPortAndAddress(nativeAddr, port, addr); //TODO: async connect with active object - from here to end of function is a mess TRequestStatus status; nativeSocket.Connect(nativeAddr, status); @@ -413,8 +367,8 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16 bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, quint16 port) { - TInetAddr nativeAddr = qt_QHostAddressToTInetAddr(address); - nativeAddr.SetPort(port); + TInetAddr nativeAddr; + setPortAndAddress(nativeAddr, port, address); TInt err = nativeSocket.Bind(nativeAddr); @@ -535,7 +489,7 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxS if (status.Int()) { setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString); } else if (port || address) { - qt_socket_getPortAndAddress(addr, port, address); + getPortAndAddress(addr, port, address); } #if defined (QNATIVESOCKETENGINE_DEBUG) @@ -555,9 +509,9 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l const QHostAddress &host, quint16 port) { TPtrC8 buffer((TUint8*)data, (int)len); - TInetAddr addr = qt_QHostAddressToTInetAddr(host); + TInetAddr addr; + setPortAndAddress(addr, port, host); TSockXfrLength sentBytes; - addr.SetPort(port); TRequestStatus status; //TODO: OMG sync send! nativeSocket.SendTo(buffer, addr, 0, status, sentBytes); User::WaitForRequest(status); @@ -592,12 +546,17 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters() if (socketDescriptor == -1) return false; - //TODO: work out how to initialise nativeSocket from socketDescriptor + if (!nativeSocket.SubSessionHandle()) { + RSocket *s = QSymbianSocketManager::instance().lookupSocket(socketDescriptor); + if (!s) + return false; + nativeSocket = *s; //TODO: badwrongfun (address is different, so this is broken) + } // Determine local address TSockAddr addr; nativeSocket.LocalName(addr); - qt_socket_getPortAndAddress(addr, &localPort, &localAddress); + getPortAndAddress(addr, &localPort, &localAddress); // Determine protocol family switch (addr.Family()) { @@ -616,7 +575,7 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters() // Determine the remote address nativeSocket.RemoteName(addr); - qt_socket_getPortAndAddress(addr, &peerPort, &peerAddress); + getPortAndAddress(addr, &peerPort, &peerAddress); // Determine the socket type (UDP/TCP) TProtocolDesc protocol; @@ -662,6 +621,7 @@ void QNativeSocketEnginePrivate::nativeClose() //TODO: call nativeSocket.Shutdown(EImmediate) in some cases? nativeSocket.Close(); + QSymbianSocketManager::instance().removeSocket(&nativeSocket); } qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len) @@ -744,13 +704,68 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize) int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const { -//TODO: implement + bool readyRead = false; + bool readyWrite = false; + if (selectForRead) + return nativeSelect(timeout, true, false, &readyRead, &readyWrite); + else + return nativeSelect(timeout, false, true, &readyRead, &readyWrite); } +/*! + \internal + \param timeout timeout in milliseconds + \param checkRead caller is interested if the socket is ready to read + \param checkWrite caller is interested if the socket is ready for write + \param selectForRead (out) should set to true if ready to read + \param selectForWrite (out) should set to true if ready to write + \return 0 on timeout, >0 on success, <0 on error + */ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool checkWrite, bool *selectForRead, bool *selectForWrite) const { //TODO: implement + //as above, but checking both read and write status at the same time + if (!selectTimer.Handle()) + qt_symbian_throwIfError(selectTimer.CreateLocal()); + TRequestStatus timerStat; + selectTimer.HighRes(timerStat, timeout * 1000); + TRequestStatus* readStat = 0; + TRequestStatus* writeStat = 0; + TRequestStatus* array[3]; + array[0] = &timerStat; + int count = 1; + if (checkRead) { + //TODO: get from read AO + //readStat = ? + array[count++] = readStat; + } + if (checkWrite) { + //TODO: get from write AO + //writeStat = ? + array[count++] = writeStat; + } + + User::WaitForNRequest(array, count); + //IMPORTANT - WaitForNRequest only decrements the thread semaphore once, although more than one status may have completed. + if (timerStat.Int() != KRequestPending) { + //timed out + return 0; + } + selectTimer.Cancel(); + User::WaitForRequest(timerStat); + + if(readStat && readStat->Int() != KRequestPending) { + Q_ASSERT(checkRead && selectForRead); + //TODO: cancel the AO, but call its RunL anyway? looking for an UnsetActive() + *selectForRead = true; + } + if(writeStat && writeStat->Int() != KRequestPending) { + Q_ASSERT(checkWrite && selectForWrite); + //TODO: cancel the AO, but call its RunL anyway? looking for an UnsetActive() + *selectForWrite = true; + } + return 1; } QT_END_NAMESPACE -- cgit v0.12 From de55502a960a1044770aa840d7e443343b3c436b Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 6 Dec 2010 12:36:13 +0000 Subject: Add socket manager to corelib This class stores socket handles so they can be passed around as integers. Also, it owns the global RSocketServ used throughout the application. Reason for this not being in QtNetwork is that QtCore exports some socket related classes. Reviewed-by: Markus Goetz --- src/corelib/kernel/qcore_symbian_p.cpp | 27 +++++++++++++++++++++------ src/corelib/kernel/qcore_symbian_p.h | 34 +++++++++++++++++++++++++++------- 2 files changed, 48 insertions(+), 13 deletions(-) diff --git a/src/corelib/kernel/qcore_symbian_p.cpp b/src/corelib/kernel/qcore_symbian_p.cpp index 29996a4..809dc30 100644 --- a/src/corelib/kernel/qcore_symbian_p.cpp +++ b/src/corelib/kernel/qcore_symbian_p.cpp @@ -203,6 +203,11 @@ private: RFs iFs; }; +uint qHash(const RSubSessionBase& key) +{ + return qHash(key.SubSessionHandle()); +} + Q_GLOBAL_STATIC(QS60RFsSession, qt_s60_RFsSession); Q_CORE_EXPORT RFs& qt_s60GetRFs() @@ -229,7 +234,8 @@ RSocketServ& QSymbianSocketManager::getSocketServer() { return iSocketServ; } -int QSymbianSocketManager::addSocket(RSocket* sock) { +int QSymbianSocketManager::addSocket(const RSocket& socket) { + QHashableSocket sock(static_cast(socket)); QMutexLocker l(&iMutex); Q_ASSERT(!socketMap.contains(sock)); if(socketMap.contains(sock)) @@ -250,7 +256,8 @@ int QSymbianSocketManager::addSocket(RSocket* sock) { return id + socket_offset; } -bool QSymbianSocketManager::removeSocket(RSocket* sock) { +bool QSymbianSocketManager::removeSocket(const RSocket &socket) { + QHashableSocket sock(static_cast(socket)); QMutexLocker l(&iMutex); if(!socketMap.contains(sock)) return false; @@ -260,7 +267,8 @@ bool QSymbianSocketManager::removeSocket(RSocket* sock) { return true; } -int QSymbianSocketManager::lookupSocket(RSocket* sock) const { +int QSymbianSocketManager::lookupSocket(const RSocket& socket) const { + QHashableSocket sock(static_cast(socket)); QMutexLocker l(&iMutex); if(!socketMap.contains(sock)) return -1; @@ -268,12 +276,13 @@ int QSymbianSocketManager::lookupSocket(RSocket* sock) const { return id + socket_offset; } -RSocket* QSymbianSocketManager::lookupSocket(int fd) const { +bool QSymbianSocketManager::lookupSocket(int fd, RSocket& socket) const { QMutexLocker l(&iMutex); int id = fd + socket_offset; if(!reverseSocketMap.contains(id)) - return 0; - return reverseSocketMap.value(id); + return false; + socket = reverseSocketMap.value(id); + return true; } Q_GLOBAL_STATIC(QSymbianSocketManager, qt_symbianSocketManager); @@ -282,4 +291,10 @@ QSymbianSocketManager& QSymbianSocketManager::instance() { return *(qt_symbianSocketManager()); } + +Q_CORE_EXPORT RSocketServ& qt_symbianGetSocketServer() +{ + return QSymbianSocketManager::instance().getSocketServer(); +} + QT_END_NAMESPACE diff --git a/src/corelib/kernel/qcore_symbian_p.h b/src/corelib/kernel/qcore_symbian_p.h index b6cba6e..8ffa247 100644 --- a/src/corelib/kernel/qcore_symbian_p.h +++ b/src/corelib/kernel/qcore_symbian_p.h @@ -161,6 +161,25 @@ Q_CORE_EXPORT RSocketServ& qt_symbianGetSocketServer(); // Defined in qlocale_symbian.cpp. Q_CORE_EXPORT QByteArray qt_symbianLocaleName(int code); +//Wrapper for RSocket so it can be used as a key in QHash or QMap +class QHashableSocket : public RSocket +{ +public: + bool operator==(const QHashableSocket &other) const + { + return SubSessionHandle() == other.SubSessionHandle() + && Session().Handle() == other.Session().Handle(); + } + bool operator<(const QHashableSocket &other) const + { + if(Session().Handle() == other.Session().Handle()) + return SubSessionHandle() < other.SubSessionHandle(); + return Session().Handle() < other.Session().Handle(); + } +}; + +uint qHash(const RSubSessionBase& key); + /*! \internal This class exists in QtCore for the benefit of QSocketNotifier, which uses integer @@ -185,28 +204,29 @@ public: \param an open socket \return pseudo file descriptor, -1 if out of resources */ - int addSocket(RSocket *sock); + int addSocket(const RSocket &sock); /*! \internal Removes a symbian socket from the global map \param an open socket \return true if the socket was in the map */ - bool removeSocket(RSocket *sock); + bool removeSocket(const RSocket &sock); /*! \internal Get pseudo file descriptor for a socket \param an open socket \return integer handle, or -1 if not in map */ - int lookupSocket(RSocket *sock) const; + int lookupSocket(const RSocket &sock) const; /*! \internal Get socket for a pseudo file descriptor \param an open socket fd - \return socket handle or NULL if not in map + \param sock (out) socket handle + \return true on success or false if not in map */ - RSocket *lookupSocket(int fd) const; + bool lookupSocket(int fd, RSocket& sock) const; /*! \internal @@ -219,8 +239,8 @@ private: const static int max_sockets = 0x20000; //covers all TCP and UDP ports, probably run out of memory first const static int socket_offset = 0x40000000; //hacky way of separating sockets from file descriptors int iNextSocket; - QHash socketMap; - QHash reverseSocketMap; + QHash socketMap; + QHash reverseSocketMap; mutable QMutex iMutex; RSocketServ iSocketServ; }; -- cgit v0.12 From 7ec11a51d564c85d46ddee270cf7c743a2cbd320 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 6 Dec 2010 14:02:02 +0000 Subject: Use socket manager in QtNetwork Store/Retrieve sockets in the socket manager Use the shared socket server instance from QtCore Also, add 4 stub functions for multicast groups (new in master) to fix link error Reviewed-by: Markus Goetz --- src/network/socket/qnativesocketengine.cpp | 17 +++++++---- src/network/socket/qnativesocketengine_p.h | 2 +- src/network/socket/qnativesocketengine_symbian.cpp | 35 ++++++++++++++++++---- 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/src/network/socket/qnativesocketengine.cpp b/src/network/socket/qnativesocketengine.cpp index df73b9c..00d36b4 100644 --- a/src/network/socket/qnativesocketengine.cpp +++ b/src/network/socket/qnativesocketengine.cpp @@ -110,6 +110,10 @@ # include "qtcpserver.h" #endif +#ifdef Q_OS_SYMBIAN +# include +#endif + QT_BEGIN_NAMESPACE //#define QNATIVESOCKETENGINE_DEBUG @@ -158,12 +162,15 @@ QT_BEGIN_NAMESPACE concurrent QNativeSocketEngine. This is safe, because WSAStartup and WSACleanup are reference counted. */ -QNativeSocketEnginePrivate::QNativeSocketEnginePrivate() +QNativeSocketEnginePrivate::QNativeSocketEnginePrivate() : + socketDescriptor(-1), +#ifdef Q_OS_SYMBIAN + socketServer(qt_symbianGetSocketServer()), +#endif + readNotifier(0), + writeNotifier(0), + exceptNotifier(0) { - socketDescriptor = -1; - readNotifier = 0; - writeNotifier = 0; - exceptNotifier = 0; } /*! \internal diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h index ceecfeb..c017065 100644 --- a/src/network/socket/qnativesocketengine_p.h +++ b/src/network/socket/qnativesocketengine_p.h @@ -200,7 +200,7 @@ public: int socketDescriptor; #ifdef Q_OS_SYMBIAN mutable RSocket nativeSocket; - RSocketServ socketServer; //TODO: shared ref + RSocketServ& socketServer; RConnection connection; //TODO: shared ref mutable RTimer selectTimer; #endif diff --git a/src/network/socket/qnativesocketengine_symbian.cpp b/src/network/socket/qnativesocketengine_symbian.cpp index 788e58a..d1a0819 100644 --- a/src/network/socket/qnativesocketengine_symbian.cpp +++ b/src/network/socket/qnativesocketengine_symbian.cpp @@ -46,6 +46,7 @@ #include "qhostaddress.h" #include "qelapsedtimer.h" #include "qvarlengtharray.h" +#include "qnetworkinterface.h" #include #include #include @@ -165,7 +166,7 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc return false; } - socketDescriptor = QSymbianSocketManager::instance().addSocket(&nativeSocket); + socketDescriptor = QSymbianSocketManager::instance().addSocket(nativeSocket); return true; } @@ -547,10 +548,8 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters() return false; if (!nativeSocket.SubSessionHandle()) { - RSocket *s = QSymbianSocketManager::instance().lookupSocket(socketDescriptor); - if (!s) + if (!QSymbianSocketManager::instance().lookupSocket(socketDescriptor, nativeSocket)) return false; - nativeSocket = *s; //TODO: badwrongfun (address is different, so this is broken) } // Determine local address @@ -621,7 +620,7 @@ void QNativeSocketEnginePrivate::nativeClose() //TODO: call nativeSocket.Shutdown(EImmediate) in some cases? nativeSocket.Close(); - QSymbianSocketManager::instance().removeSocket(&nativeSocket); + QSymbianSocketManager::instance().removeSocket(nativeSocket); } qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len) @@ -768,4 +767,30 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool c return 1; } +bool QNativeSocketEnginePrivate::nativeJoinMulticastGroup(const QHostAddress &groupAddress, + const QNetworkInterface &iface) +{ + //TODO + return false; +} + +bool QNativeSocketEnginePrivate::nativeLeaveMulticastGroup(const QHostAddress &groupAddress, + const QNetworkInterface &iface) +{ + //TODO + return false; +} + +QNetworkInterface QNativeSocketEnginePrivate::nativeMulticastInterface() const +{ + //TODO + return QNetworkInterface(); +} + +bool QNativeSocketEnginePrivate::nativeSetMulticastInterface(const QNetworkInterface &iface) +{ + //TODO + return false; +} + QT_END_NAMESPACE -- cgit v0.12 From 8dacbccfd89006d1571b3b6ab6e96ea13e74f455 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 6 Dec 2010 15:47:40 +0000 Subject: Set preferences in socket server Connect() Tell the socket server we intend to use this session mainly for IP This allows the socket server to optimise this session for IP usage. Reviewed-by: Markus Goetz --- src/corelib/kernel/qcore_symbian_p.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/corelib/kernel/qcore_symbian_p.cpp b/src/corelib/kernel/qcore_symbian_p.cpp index 809dc30..b6688f7 100644 --- a/src/corelib/kernel/qcore_symbian_p.cpp +++ b/src/corelib/kernel/qcore_symbian_p.cpp @@ -44,6 +44,7 @@ #include #include "qcore_symbian_p.h" #include +#include QT_BEGIN_NAMESPACE @@ -218,7 +219,11 @@ Q_CORE_EXPORT RFs& qt_s60GetRFs() QSymbianSocketManager::QSymbianSocketManager() : iNextSocket(0) { - qt_symbian_throwIfError(iSocketServ.Connect()); + TSessionPref preferences; + // ### In future this could be changed to KAfInet6 when that is more common than IPv4 + preferences.iAddrFamily = KAfInet; + preferences.iProtocol = KProtocolInetIp; + qt_symbian_throwIfError(iSocketServ.Connect(preferences)); qt_symbian_throwIfError(iSocketServ.ShareAuto()); } -- cgit v0.12 From 5ef1fb5823a25cd4b27029701f7d707c82750acb Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 6 Dec 2010 15:57:59 +0000 Subject: Use shared socket server session everywhere Converted uses of RSocketServ in QtNetwork and the symbian bearer plugin to use the shared session from QtCore instead of creating their own Reviewed-by: Markus Goetz --- src/network/kernel/qnetworkinterface_symbian.cpp | 13 ++----------- src/plugins/bearer/symbian/qnetworksession_impl.cpp | 18 +++--------------- src/plugins/bearer/symbian/qnetworksession_impl.h | 2 +- 3 files changed, 6 insertions(+), 27 deletions(-) diff --git a/src/network/kernel/qnetworkinterface_symbian.cpp b/src/network/kernel/qnetworkinterface_symbian.cpp index 7942461..751664e 100644 --- a/src/network/kernel/qnetworkinterface_symbian.cpp +++ b/src/network/kernel/qnetworkinterface_symbian.cpp @@ -44,6 +44,7 @@ #include "qnetworkinterface.h" #include "qnetworkinterface_p.h" #include "../corelib/kernel/qcore_symbian_p.h" +#include #ifndef QT_NO_NETWORKINTERFACE @@ -72,17 +73,10 @@ static QList interfaceListing() TInt err(KErrNone); QList interfaces; - // Connect to Native socket server - RSocketServ socketServ; - err = socketServ.Connect(); - if (err) - return interfaces; - // Open dummy socket for interface queries RSocket socket; - err = socket.Open(socketServ, _L("udp")); + err = socket.Open(qt_symbianGetSocketServer(), _L("udp")); if (err) { - socketServ.Close(); return interfaces; } @@ -90,7 +84,6 @@ static QList interfaceListing() err = socket.SetOpt(KSoInetEnumInterfaces, KSolInetIfCtrl); if (err) { socket.Close(); - socketServ.Close(); return interfaces; } @@ -176,7 +169,6 @@ static QList interfaceListing() err = socket.SetOpt(KSoInetEnumRoutes, KSolInetRtCtrl); if (err) { socket.Close(); - socketServ.Close(); // return what we have // up to this moment return interfaces; @@ -223,7 +215,6 @@ static QList interfaceListing() } socket.Close(); - socketServ.Close(); return interfaces; } diff --git a/src/plugins/bearer/symbian/qnetworksession_impl.cpp b/src/plugins/bearer/symbian/qnetworksession_impl.cpp index 53a5b4d..cfb55bf 100644 --- a/src/plugins/bearer/symbian/qnetworksession_impl.cpp +++ b/src/plugins/bearer/symbian/qnetworksession_impl.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #ifdef SNAP_FUNCTIONALITY_AVAILABLE #include @@ -65,7 +66,7 @@ QNetworkSessionPrivateImpl::QNetworkSessionPrivateImpl(SymbianEngine *engine) iDynamicUnSetdefaultif(0), ipConnectionNotifier(0), iHandleStateNotificationsFromManager(false), iFirstSync(true), iStoppedByUser(false), iClosedByUser(false), iError(QNetworkSession::UnknownSessionError), iALREnabled(0), - iConnectInBackground(false), isOpening(false) + iConnectInBackground(false), isOpening(false), iSocketServ(qt_symbianGetSocketServer()) { CActiveScheduler::Add(this); @@ -109,7 +110,6 @@ QNetworkSessionPrivateImpl::~QNetworkSessionPrivateImpl() // Cancel possible RConnection::Start() Cancel(); - iSocketServ.Close(); // Close global 'Open C' RConnection // Clears also possible unsetdefaultif() flags. @@ -363,20 +363,9 @@ void QNetworkSessionPrivateImpl::open() iStoppedByUser = false; iClosedByUser = false; - TInt error = iSocketServ.Connect(); - if (error != KErrNone) { - // Could not open RSocketServ - newState(QNetworkSession::Invalid); - iError = QNetworkSession::UnknownSessionError; - emit QNetworkSessionPrivate::error(iError); - syncStateWithInterface(); - return; - } - - error = iConnection.Open(iSocketServ); + TInt error = iConnection.Open(iSocketServ); if (error != KErrNone) { // Could not open RConnection - iSocketServ.Close(); newState(QNetworkSession::Invalid); iError = QNetworkSession::UnknownSessionError; emit QNetworkSessionPrivate::error(iError); @@ -533,7 +522,6 @@ void QNetworkSessionPrivateImpl::close(bool allowSignals) } Cancel(); // closes iConnection - iSocketServ.Close(); // Close global 'Open C' RConnection. If OpenC supports, // close the defaultif for good to avoid difficult timing diff --git a/src/plugins/bearer/symbian/qnetworksession_impl.h b/src/plugins/bearer/symbian/qnetworksession_impl.h index 8e3e997..1101d1e 100644 --- a/src/plugins/bearer/symbian/qnetworksession_impl.h +++ b/src/plugins/bearer/symbian/qnetworksession_impl.h @@ -162,7 +162,7 @@ private: // data RLibrary iOpenCLibrary; TOpenCUnSetdefaultifFunction iDynamicUnSetdefaultif; - mutable RSocketServ iSocketServ; + mutable RSocketServ &iSocketServ; //not owned, shared from QtCore mutable RConnection iConnection; mutable RConnectionMonitor iConnectionMonitor; ConnectionProgressNotifier* ipConnectionNotifier; -- cgit v0.12 From 3a53b2853c0f1d4ace0eaf73f8c5ca5ded172345 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Tue, 7 Dec 2010 09:23:04 +0100 Subject: Symbian socket engine: Some more comments --- src/network/socket/qnativesocketengine_symbian.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/network/socket/qnativesocketengine_symbian.cpp b/src/network/socket/qnativesocketengine_symbian.cpp index d1a0819..cfaee03 100644 --- a/src/network/socket/qnativesocketengine_symbian.cpp +++ b/src/network/socket/qnativesocketengine_symbian.cpp @@ -165,6 +165,9 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc return false; } + // FIXME Set socket to nonblocking. While we are still a QNativeSocketEngine this is done already. + // Uncomment the following when we switch to QSymbianSocketEngine. + // setOption(NonBlockingSocketOption, 1) socketDescriptor = QSymbianSocketManager::instance().addSocket(nativeSocket); return true; @@ -444,7 +447,8 @@ int QNativeSocketEnginePrivate::nativeAccept() qWarning("QNativeSocketEnginePrivate::nativeAccept() - error %d", status.Int()); return 0; } - + // FIXME Qt Handle of new socket must be retrieved from QSymbianSocketManager + // and then returned. Not the SubSessionHandle! Also set the socket to nonblocking. return blankSocket.SubSessionHandle(); } @@ -452,6 +456,8 @@ qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const { int nbytes = 0; qint64 available = 0; + // FIXME is this the right thing also for UDP? + // What is expected for UDP, the length for the next packet I guess? TInt err = nativeSocket.GetOpt(KSOReadBytesPending, KSOLSocket, nbytes); if(err) return 0; @@ -476,6 +482,8 @@ qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const int nbytes; TInt err = nativeSocket.GetOpt(KSOReadBytesPending,KSOLSocket, nbytes); return qint64(nbytes-28); //TODO: why -28 (open C version had this)? + // Why = Could it be that this is about header lengths etc? if yes + // this could be pretty broken, especially for IPv6 } qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxSize, @@ -744,6 +752,8 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool c //writeStat = ? array[count++] = writeStat; } + // TODO: for selecting, we can use getOpt(KSOSelectPoll) to get the select result + // and KIOCtlSelect for the selecting. User::WaitForNRequest(array, count); //IMPORTANT - WaitForNRequest only decrements the thread semaphore once, although more than one status may have completed. -- cgit v0.12 From fcb60092c90934df77f1441df7ab2a14fc5edf32 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Tue, 7 Dec 2010 09:43:07 +0100 Subject: Copy qhostinfo_unix.cpp to qhostinfo_symbian.cpp --- src/network/kernel/kernel.pri | 2 +- src/network/kernel/qhostinfo_symbian.cpp | 407 +++++++++++++++++++++++++++++++ 2 files changed, 408 insertions(+), 1 deletion(-) create mode 100644 src/network/kernel/qhostinfo_symbian.cpp diff --git a/src/network/kernel/kernel.pri b/src/network/kernel/kernel.pri index 6145c43..ccc113c 100644 --- a/src/network/kernel/kernel.pri +++ b/src/network/kernel/kernel.pri @@ -20,7 +20,7 @@ SOURCES += kernel/qauthenticator.cpp \ kernel/qnetworkproxy.cpp \ kernel/qnetworkinterface.cpp -symbian: SOURCES += kernel/qhostinfo_unix.cpp kernel/qnetworkinterface_symbian.cpp +symbian: SOURCES += kernel/qhostinfo_symbian.cpp kernel/qnetworkinterface_symbian.cpp unix:!symbian:SOURCES += kernel/qhostinfo_unix.cpp kernel/qnetworkinterface_unix.cpp win32:SOURCES += kernel/qhostinfo_win.cpp kernel/qnetworkinterface_win.cpp diff --git a/src/network/kernel/qhostinfo_symbian.cpp b/src/network/kernel/qhostinfo_symbian.cpp new file mode 100644 index 0000000..5ca15a3 --- /dev/null +++ b/src/network/kernel/qhostinfo_symbian.cpp @@ -0,0 +1,407 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +//#define QHOSTINFO_DEBUG + +#include "qplatformdefs.h" + +#include "qhostinfo_p.h" +#include "private/qnativesocketengine_p.h" +#include "qiodevice.h" +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#if defined(Q_OS_VXWORKS) +# include +#else +# include +#endif + +#if defined (QT_NO_GETADDRINFO) +#include +QT_BEGIN_NAMESPACE +Q_GLOBAL_STATIC(QMutex, getHostByNameMutex) +QT_END_NAMESPACE +#endif + +QT_BEGIN_NAMESPACE + +// Almost always the same. If not, specify in qplatformdefs.h. +#if !defined(QT_SOCKOPTLEN_T) +# define QT_SOCKOPTLEN_T QT_SOCKLEN_T +#endif + +// HP-UXi has a bug in getaddrinfo(3) that makes it thread-unsafe +// with this flag. So disable it in that platform. +#if defined(AI_ADDRCONFIG) && !defined(Q_OS_HPUX) +# define Q_ADDRCONFIG AI_ADDRCONFIG +#endif + +typedef struct __res_state *res_state_ptr; + +typedef int (*res_init_proto)(void); +static res_init_proto local_res_init = 0; +typedef int (*res_ninit_proto)(res_state_ptr); +static res_ninit_proto local_res_ninit = 0; +typedef void (*res_nclose_proto)(res_state_ptr); +static res_nclose_proto local_res_nclose = 0; +static res_state_ptr local_res = 0; + +static void resolveLibrary() +{ +#ifndef QT_NO_LIBRARY + QLibrary lib(QLatin1String("resolv")); + if (!lib.load()) + return; + + local_res_init = res_init_proto(lib.resolve("__res_init")); + if (!local_res_init) + local_res_init = res_init_proto(lib.resolve("res_init")); + + local_res_ninit = res_ninit_proto(lib.resolve("__res_ninit")); + if (!local_res_ninit) + local_res_ninit = res_ninit_proto(lib.resolve("res_ninit")); + + if (!local_res_ninit) { + // if we can't get a thread-safe context, we have to use the global _res state + local_res = res_state_ptr(lib.resolve("_res")); + } else { + local_res_nclose = res_nclose_proto(lib.resolve("res_nclose")); + if (!local_res_nclose) + local_res_nclose = res_nclose_proto(lib.resolve("__res_nclose")); + if (!local_res_nclose) + local_res_ninit = 0; + } +#endif +} + +QHostInfo QHostInfoAgent::fromName(const QString &hostName) +{ + QHostInfo results; + +#if defined(QHOSTINFO_DEBUG) + qDebug("QHostInfoAgent::fromName(%s) looking up...", + hostName.toLatin1().constData()); +#endif + + // Load res_init on demand. + static volatile bool triedResolve = false; + if (!triedResolve) { + QMutexLocker locker(QMutexPool::globalInstanceGet(&local_res_init)); + if (!triedResolve) { + resolveLibrary(); + triedResolve = true; + } + } + + // If res_init is available, poll it. + if (local_res_init) + local_res_init(); + + QHostAddress address; + if (address.setAddress(hostName)) { + // Reverse lookup +// Reverse lookups using getnameinfo are broken on darwin, use gethostbyaddr instead. +#if !defined (QT_NO_GETADDRINFO) && !defined (Q_OS_DARWIN) && !defined (Q_OS_SYMBIAN) + sockaddr_in sa4; +#ifndef QT_NO_IPV6 + sockaddr_in6 sa6; +#endif + sockaddr *sa = 0; + QT_SOCKLEN_T saSize = 0; + if (address.protocol() == QAbstractSocket::IPv4Protocol) { + sa = (sockaddr *)&sa4; + saSize = sizeof(sa4); + memset(&sa4, 0, sizeof(sa4)); + sa4.sin_family = AF_INET; + sa4.sin_addr.s_addr = htonl(address.toIPv4Address()); + } +#ifndef QT_NO_IPV6 + else { + sa = (sockaddr *)&sa6; + saSize = sizeof(sa6); + memset(&sa6, 0, sizeof(sa6)); + sa6.sin6_family = AF_INET6; + memcpy(sa6.sin6_addr.s6_addr, address.toIPv6Address().c, sizeof(sa6.sin6_addr.s6_addr)); + } +#endif + + char hbuf[NI_MAXHOST]; + if (sa && getnameinfo(sa, saSize, hbuf, sizeof(hbuf), 0, 0, 0) == 0) + results.setHostName(QString::fromLatin1(hbuf)); +#else + in_addr_t inetaddr = qt_safe_inet_addr(hostName.toLatin1().constData()); + struct hostent *ent = gethostbyaddr((const char *)&inetaddr, sizeof(inetaddr), AF_INET); + if (ent) + results.setHostName(QString::fromLatin1(ent->h_name)); +#endif + + if (results.hostName().isEmpty()) + results.setHostName(address.toString()); + results.setAddresses(QList() << address); + return results; + } + + // IDN support + QByteArray aceHostname = QUrl::toAce(hostName); + results.setHostName(hostName); + if (aceHostname.isEmpty()) { + results.setError(QHostInfo::HostNotFound); + results.setErrorString(hostName.isEmpty() ? + QCoreApplication::translate("QHostInfoAgent", "No host name given") : + QCoreApplication::translate("QHostInfoAgent", "Invalid hostname")); + return results; + } + +#if !defined (QT_NO_GETADDRINFO) + // Call getaddrinfo, and place all IPv4 addresses at the start and + // the IPv6 addresses at the end of the address list in results. + addrinfo *res = 0; + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; +#ifdef Q_ADDRCONFIG + hints.ai_flags = Q_ADDRCONFIG; +#endif +#ifdef Q_OS_SYMBIAN +# ifdef QHOSTINFO_DEBUG + qDebug() << "Setting flags: 'hints.ai_flags &= AI_V4MAPPED | AI_ALL'"; +# endif +#endif + + int result = getaddrinfo(aceHostname.constData(), 0, &hints, &res); +# ifdef Q_ADDRCONFIG + if (result == EAI_BADFLAGS) { + // if the lookup failed with AI_ADDRCONFIG set, try again without it + hints.ai_flags = 0; +#ifdef Q_OS_SYMBIAN +# ifdef QHOSTINFO_DEBUG + qDebug() << "Setting flags: 'hints.ai_flags &= AI_V4MAPPED | AI_ALL'"; +# endif + hints.ai_flags &= AI_V4MAPPED | AI_ALL; +#endif + result = getaddrinfo(aceHostname.constData(), 0, &hints, &res); + } +# endif + + if (result == 0) { + addrinfo *node = res; + QList addresses; + while (node) { +#ifdef QHOSTINFO_DEBUG + qDebug() << "getaddrinfo node: flags:" << node->ai_flags << "family:" << node->ai_family << "ai_socktype:" << node->ai_socktype << "ai_protocol:" << node->ai_protocol << "ai_addrlen:" << node->ai_addrlen; +#endif + if (node->ai_family == AF_INET) { + QHostAddress addr; + addr.setAddress(ntohl(((sockaddr_in *) node->ai_addr)->sin_addr.s_addr)); + if (!addresses.contains(addr)) + addresses.append(addr); + } +#ifndef QT_NO_IPV6 + else if (node->ai_family == AF_INET6) { + QHostAddress addr; + sockaddr_in6 *sa6 = (sockaddr_in6 *) node->ai_addr; + addr.setAddress(sa6->sin6_addr.s6_addr); + if (sa6->sin6_scope_id) + addr.setScopeId(QString::number(sa6->sin6_scope_id)); + if (!addresses.contains(addr)) + addresses.append(addr); + } +#endif + node = node->ai_next; + } + if (addresses.isEmpty() && node == 0) { + // Reached the end of the list, but no addresses were found; this + // means the list contains one or more unknown address types. + results.setError(QHostInfo::UnknownError); + results.setErrorString(tr("Unknown address type")); + } + + results.setAddresses(addresses); + freeaddrinfo(res); + } else if (result == EAI_NONAME + || result == EAI_FAIL +#ifdef EAI_NODATA + // EAI_NODATA is deprecated in RFC 3493 + || result == EAI_NODATA +#endif + ) { + results.setError(QHostInfo::HostNotFound); + results.setErrorString(tr("Host not found")); + } else { + results.setError(QHostInfo::UnknownError); + results.setErrorString(QString::fromLocal8Bit(gai_strerror(result))); + } + +#else + // Fall back to gethostbyname for platforms that don't define + // getaddrinfo. gethostbyname does not support IPv6, and it's not + // reentrant on all platforms. For now this is okay since we only + // use one QHostInfoAgent, but if more agents are introduced, locking + // must be provided. + QMutexLocker locker(::getHostByNameMutex()); + hostent *result = gethostbyname(aceHostname.constData()); + if (result) { + if (result->h_addrtype == AF_INET) { + QList addresses; + for (char **p = result->h_addr_list; *p != 0; p++) { + QHostAddress addr; + addr.setAddress(ntohl(*((quint32 *)*p))); + if (!addresses.contains(addr)) + addresses.prepend(addr); + } + results.setAddresses(addresses); + } else { + results.setError(QHostInfo::UnknownError); + results.setErrorString(tr("Unknown address type")); + } +#if !defined(Q_OS_VXWORKS) + } else if (h_errno == HOST_NOT_FOUND || h_errno == NO_DATA + || h_errno == NO_ADDRESS) { + results.setError(QHostInfo::HostNotFound); + results.setErrorString(tr("Host not found")); +#endif + } else { + results.setError(QHostInfo::UnknownError); + results.setErrorString(tr("Unknown error")); + } +#endif // !defined (QT_NO_GETADDRINFO) + +#if defined(QHOSTINFO_DEBUG) + if (results.error() != QHostInfo::NoError) { + qDebug("QHostInfoAgent::fromName(): error #%d %s", + h_errno, results.errorString().toLatin1().constData()); + } else { + QString tmp; + QList addresses = results.addresses(); + for (int i = 0; i < addresses.count(); ++i) { + if (i != 0) tmp += ", "; + tmp += addresses.at(i).toString(); + } + qDebug("QHostInfoAgent::fromName(): found %i entries for \"%s\": {%s}", + addresses.count(), hostName.toLatin1().constData(), + tmp.toLatin1().constData()); + } +#endif + return results; +} + +QString QHostInfo::localHostName() +{ + char hostName[512]; + if (gethostname(hostName, sizeof(hostName)) == -1) + return QString(); + hostName[sizeof(hostName) - 1] = '\0'; + return QString::fromLocal8Bit(hostName); +} + +QString QHostInfo::localDomainName() +{ +#if !defined(Q_OS_VXWORKS) + resolveLibrary(); + if (local_res_ninit) { + // using thread-safe version + res_state_ptr state = res_state_ptr(qMalloc(sizeof(*state))); + Q_CHECK_PTR(state); + memset(state, 0, sizeof(*state)); + local_res_ninit(state); + QString domainName = QUrl::fromAce(state->defdname); + if (domainName.isEmpty()) + domainName = QUrl::fromAce(state->dnsrch[0]); + local_res_nclose(state); + qFree(state); + + return domainName; + } + + if (local_res_init && local_res) { + // using thread-unsafe version + +#if defined(QT_NO_GETADDRINFO) + // We have to call res_init to be sure that _res was initialized + // So, for systems without getaddrinfo (which is thread-safe), we lock the mutex too + QMutexLocker locker(::getHostByNameMutex()); +#endif + local_res_init(); + QString domainName = QUrl::fromAce(local_res->defdname); + if (domainName.isEmpty()) + domainName = QUrl::fromAce(local_res->dnsrch[0]); + return domainName; + } +#endif + // nothing worked, try doing it by ourselves: + QFile resolvconf; +#if defined(_PATH_RESCONF) + resolvconf.setFileName(QFile::decodeName(_PATH_RESCONF)); +#else + resolvconf.setFileName(QLatin1String("/etc/resolv.conf")); +#endif + if (!resolvconf.open(QIODevice::ReadOnly)) + return QString(); // failure + + QString domainName; + while (!resolvconf.atEnd()) { + QByteArray line = resolvconf.readLine().trimmed(); + if (line.startsWith("domain ")) + return QUrl::fromAce(line.mid(sizeof "domain " - 1).trimmed()); + + // in case there's no "domain" line, fall back to the first "search" entry + if (domainName.isEmpty() && line.startsWith("search ")) { + QByteArray searchDomain = line.mid(sizeof "search " - 1).trimmed(); + int pos = searchDomain.indexOf(' '); + if (pos != -1) + searchDomain.truncate(pos); + domainName = QUrl::fromAce(searchDomain); + } + } + + // return the fallen-back-to searched domain + return domainName; +} + +QT_END_NAMESPACE -- cgit v0.12 From 5c75d5bed133a4cd77329b5e90d1f47f86f92a17 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Tue, 7 Dec 2010 10:01:08 +0100 Subject: Weed out old unix code from qhostinfo_symbian.cpp --- src/network/kernel/qhostinfo_symbian.cpp | 322 +------------------------------ 1 file changed, 9 insertions(+), 313 deletions(-) diff --git a/src/network/kernel/qhostinfo_symbian.cpp b/src/network/kernel/qhostinfo_symbian.cpp index 5ca15a3..2e1e6ca 100644 --- a/src/network/kernel/qhostinfo_symbian.cpp +++ b/src/network/kernel/qhostinfo_symbian.cpp @@ -44,82 +44,9 @@ #include "qplatformdefs.h" #include "qhostinfo_p.h" -#include "private/qnativesocketengine_p.h" -#include "qiodevice.h" -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#if defined(Q_OS_VXWORKS) -# include -#else -# include -#endif - -#if defined (QT_NO_GETADDRINFO) -#include -QT_BEGIN_NAMESPACE -Q_GLOBAL_STATIC(QMutex, getHostByNameMutex) -QT_END_NAMESPACE -#endif QT_BEGIN_NAMESPACE -// Almost always the same. If not, specify in qplatformdefs.h. -#if !defined(QT_SOCKOPTLEN_T) -# define QT_SOCKOPTLEN_T QT_SOCKLEN_T -#endif - -// HP-UXi has a bug in getaddrinfo(3) that makes it thread-unsafe -// with this flag. So disable it in that platform. -#if defined(AI_ADDRCONFIG) && !defined(Q_OS_HPUX) -# define Q_ADDRCONFIG AI_ADDRCONFIG -#endif - -typedef struct __res_state *res_state_ptr; - -typedef int (*res_init_proto)(void); -static res_init_proto local_res_init = 0; -typedef int (*res_ninit_proto)(res_state_ptr); -static res_ninit_proto local_res_ninit = 0; -typedef void (*res_nclose_proto)(res_state_ptr); -static res_nclose_proto local_res_nclose = 0; -static res_state_ptr local_res = 0; - -static void resolveLibrary() -{ -#ifndef QT_NO_LIBRARY - QLibrary lib(QLatin1String("resolv")); - if (!lib.load()) - return; - - local_res_init = res_init_proto(lib.resolve("__res_init")); - if (!local_res_init) - local_res_init = res_init_proto(lib.resolve("res_init")); - - local_res_ninit = res_ninit_proto(lib.resolve("__res_ninit")); - if (!local_res_ninit) - local_res_ninit = res_ninit_proto(lib.resolve("res_ninit")); - - if (!local_res_ninit) { - // if we can't get a thread-safe context, we have to use the global _res state - local_res = res_state_ptr(lib.resolve("_res")); - } else { - local_res_nclose = res_nclose_proto(lib.resolve("res_nclose")); - if (!local_res_nclose) - local_res_nclose = res_nclose_proto(lib.resolve("__res_nclose")); - if (!local_res_nclose) - local_res_ninit = 0; - } -#endif -} - QHostInfo QHostInfoAgent::fromName(const QString &hostName) { QHostInfo results; @@ -129,60 +56,11 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) hostName.toLatin1().constData()); #endif - // Load res_init on demand. - static volatile bool triedResolve = false; - if (!triedResolve) { - QMutexLocker locker(QMutexPool::globalInstanceGet(&local_res_init)); - if (!triedResolve) { - resolveLibrary(); - triedResolve = true; - } - } - - // If res_init is available, poll it. - if (local_res_init) - local_res_init(); - QHostAddress address; if (address.setAddress(hostName)) { // Reverse lookup -// Reverse lookups using getnameinfo are broken on darwin, use gethostbyaddr instead. -#if !defined (QT_NO_GETADDRINFO) && !defined (Q_OS_DARWIN) && !defined (Q_OS_SYMBIAN) - sockaddr_in sa4; -#ifndef QT_NO_IPV6 - sockaddr_in6 sa6; -#endif - sockaddr *sa = 0; - QT_SOCKLEN_T saSize = 0; - if (address.protocol() == QAbstractSocket::IPv4Protocol) { - sa = (sockaddr *)&sa4; - saSize = sizeof(sa4); - memset(&sa4, 0, sizeof(sa4)); - sa4.sin_family = AF_INET; - sa4.sin_addr.s_addr = htonl(address.toIPv4Address()); - } -#ifndef QT_NO_IPV6 - else { - sa = (sockaddr *)&sa6; - saSize = sizeof(sa6); - memset(&sa6, 0, sizeof(sa6)); - sa6.sin6_family = AF_INET6; - memcpy(sa6.sin6_addr.s6_addr, address.toIPv6Address().c, sizeof(sa6.sin6_addr.s6_addr)); - } -#endif - - char hbuf[NI_MAXHOST]; - if (sa && getnameinfo(sa, saSize, hbuf, sizeof(hbuf), 0, 0, 0) == 0) - results.setHostName(QString::fromLatin1(hbuf)); -#else - in_addr_t inetaddr = qt_safe_inet_addr(hostName.toLatin1().constData()); - struct hostent *ent = gethostbyaddr((const char *)&inetaddr, sizeof(inetaddr), AF_INET); - if (ent) - results.setHostName(QString::fromLatin1(ent->h_name)); -#endif - - if (results.hostName().isEmpty()) - results.setHostName(address.toString()); + // TODO + results.setHostName("assume.it.works"); results.setAddresses(QList() << address); return results; } @@ -198,210 +76,28 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) return results; } -#if !defined (QT_NO_GETADDRINFO) // Call getaddrinfo, and place all IPv4 addresses at the start and // the IPv6 addresses at the end of the address list in results. - addrinfo *res = 0; - struct addrinfo hints; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; -#ifdef Q_ADDRCONFIG - hints.ai_flags = Q_ADDRCONFIG; -#endif -#ifdef Q_OS_SYMBIAN -# ifdef QHOSTINFO_DEBUG - qDebug() << "Setting flags: 'hints.ai_flags &= AI_V4MAPPED | AI_ALL'"; -# endif -#endif - - int result = getaddrinfo(aceHostname.constData(), 0, &hints, &res); -# ifdef Q_ADDRCONFIG - if (result == EAI_BADFLAGS) { - // if the lookup failed with AI_ADDRCONFIG set, try again without it - hints.ai_flags = 0; -#ifdef Q_OS_SYMBIAN -# ifdef QHOSTINFO_DEBUG - qDebug() << "Setting flags: 'hints.ai_flags &= AI_V4MAPPED | AI_ALL'"; -# endif - hints.ai_flags &= AI_V4MAPPED | AI_ALL; -#endif - result = getaddrinfo(aceHostname.constData(), 0, &hints, &res); - } -# endif - - if (result == 0) { - addrinfo *node = res; - QList addresses; - while (node) { -#ifdef QHOSTINFO_DEBUG - qDebug() << "getaddrinfo node: flags:" << node->ai_flags << "family:" << node->ai_family << "ai_socktype:" << node->ai_socktype << "ai_protocol:" << node->ai_protocol << "ai_addrlen:" << node->ai_addrlen; -#endif - if (node->ai_family == AF_INET) { - QHostAddress addr; - addr.setAddress(ntohl(((sockaddr_in *) node->ai_addr)->sin_addr.s_addr)); - if (!addresses.contains(addr)) - addresses.append(addr); - } -#ifndef QT_NO_IPV6 - else if (node->ai_family == AF_INET6) { - QHostAddress addr; - sockaddr_in6 *sa6 = (sockaddr_in6 *) node->ai_addr; - addr.setAddress(sa6->sin6_addr.s6_addr); - if (sa6->sin6_scope_id) - addr.setScopeId(QString::number(sa6->sin6_scope_id)); - if (!addresses.contains(addr)) - addresses.append(addr); - } -#endif - node = node->ai_next; - } - if (addresses.isEmpty() && node == 0) { - // Reached the end of the list, but no addresses were found; this - // means the list contains one or more unknown address types. - results.setError(QHostInfo::UnknownError); - results.setErrorString(tr("Unknown address type")); - } - - results.setAddresses(addresses); - freeaddrinfo(res); - } else if (result == EAI_NONAME - || result == EAI_FAIL -#ifdef EAI_NODATA - // EAI_NODATA is deprecated in RFC 3493 - || result == EAI_NODATA -#endif - ) { - results.setError(QHostInfo::HostNotFound); - results.setErrorString(tr("Host not found")); + /* + results.setError(QHostInfo::HostNotFound); + results.setErrorString(tr("Host not found")); } else { results.setError(QHostInfo::UnknownError); results.setErrorString(QString::fromLocal8Bit(gai_strerror(result))); } - -#else - // Fall back to gethostbyname for platforms that don't define - // getaddrinfo. gethostbyname does not support IPv6, and it's not - // reentrant on all platforms. For now this is okay since we only - // use one QHostInfoAgent, but if more agents are introduced, locking - // must be provided. - QMutexLocker locker(::getHostByNameMutex()); - hostent *result = gethostbyname(aceHostname.constData()); - if (result) { - if (result->h_addrtype == AF_INET) { - QList addresses; - for (char **p = result->h_addr_list; *p != 0; p++) { - QHostAddress addr; - addr.setAddress(ntohl(*((quint32 *)*p))); - if (!addresses.contains(addr)) - addresses.prepend(addr); - } - results.setAddresses(addresses); - } else { - results.setError(QHostInfo::UnknownError); - results.setErrorString(tr("Unknown address type")); - } -#if !defined(Q_OS_VXWORKS) - } else if (h_errno == HOST_NOT_FOUND || h_errno == NO_DATA - || h_errno == NO_ADDRESS) { - results.setError(QHostInfo::HostNotFound); - results.setErrorString(tr("Host not found")); -#endif - } else { - results.setError(QHostInfo::UnknownError); - results.setErrorString(tr("Unknown error")); - } -#endif // !defined (QT_NO_GETADDRINFO) - -#if defined(QHOSTINFO_DEBUG) - if (results.error() != QHostInfo::NoError) { - qDebug("QHostInfoAgent::fromName(): error #%d %s", - h_errno, results.errorString().toLatin1().constData()); - } else { - QString tmp; - QList addresses = results.addresses(); - for (int i = 0; i < addresses.count(); ++i) { - if (i != 0) tmp += ", "; - tmp += addresses.at(i).toString(); - } - qDebug("QHostInfoAgent::fromName(): found %i entries for \"%s\": {%s}", - addresses.count(), hostName.toLatin1().constData(), - tmp.toLatin1().constData()); - } -#endif + */ + return results; } QString QHostInfo::localHostName() { - char hostName[512]; - if (gethostname(hostName, sizeof(hostName)) == -1) - return QString(); - hostName[sizeof(hostName) - 1] = '\0'; - return QString::fromLocal8Bit(hostName); + return QString() } QString QHostInfo::localDomainName() { -#if !defined(Q_OS_VXWORKS) - resolveLibrary(); - if (local_res_ninit) { - // using thread-safe version - res_state_ptr state = res_state_ptr(qMalloc(sizeof(*state))); - Q_CHECK_PTR(state); - memset(state, 0, sizeof(*state)); - local_res_ninit(state); - QString domainName = QUrl::fromAce(state->defdname); - if (domainName.isEmpty()) - domainName = QUrl::fromAce(state->dnsrch[0]); - local_res_nclose(state); - qFree(state); - - return domainName; - } - - if (local_res_init && local_res) { - // using thread-unsafe version - -#if defined(QT_NO_GETADDRINFO) - // We have to call res_init to be sure that _res was initialized - // So, for systems without getaddrinfo (which is thread-safe), we lock the mutex too - QMutexLocker locker(::getHostByNameMutex()); -#endif - local_res_init(); - QString domainName = QUrl::fromAce(local_res->defdname); - if (domainName.isEmpty()) - domainName = QUrl::fromAce(local_res->dnsrch[0]); - return domainName; - } -#endif - // nothing worked, try doing it by ourselves: - QFile resolvconf; -#if defined(_PATH_RESCONF) - resolvconf.setFileName(QFile::decodeName(_PATH_RESCONF)); -#else - resolvconf.setFileName(QLatin1String("/etc/resolv.conf")); -#endif - if (!resolvconf.open(QIODevice::ReadOnly)) - return QString(); // failure - - QString domainName; - while (!resolvconf.atEnd()) { - QByteArray line = resolvconf.readLine().trimmed(); - if (line.startsWith("domain ")) - return QUrl::fromAce(line.mid(sizeof "domain " - 1).trimmed()); - - // in case there's no "domain" line, fall back to the first "search" entry - if (domainName.isEmpty() && line.startsWith("search ")) { - QByteArray searchDomain = line.mid(sizeof "search " - 1).trimmed(); - int pos = searchDomain.indexOf(' '); - if (pos != -1) - searchDomain.truncate(pos); - domainName = QUrl::fromAce(searchDomain); - } - } - - // return the fallen-back-to searched domain - return domainName; + return QString(); } QT_END_NAMESPACE -- cgit v0.12 From 2533c00db1851e712b036329d6cc7562fe106da1 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Tue, 7 Dec 2010 10:50:45 +0100 Subject: Added qnetworkproxy_symbian.cpp --- src/network/kernel/kernel.pri | 1 + src/network/kernel/qnetworkproxy_symbian.cpp | 61 ++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 src/network/kernel/qnetworkproxy_symbian.cpp diff --git a/src/network/kernel/kernel.pri b/src/network/kernel/kernel.pri index ccc113c..8aeb5c2 100644 --- a/src/network/kernel/kernel.pri +++ b/src/network/kernel/kernel.pri @@ -27,5 +27,6 @@ win32:SOURCES += kernel/qhostinfo_win.cpp kernel/qnetworkinterface_win.cpp mac:LIBS_PRIVATE += -framework SystemConfiguration -framework CoreFoundation mac:SOURCES += kernel/qnetworkproxy_mac.cpp else:win32:SOURCES += kernel/qnetworkproxy_win.cpp +else:symbian:SOURCES += kernel/qnetworkproxy_symbian.cpp else:SOURCES += kernel/qnetworkproxy_generic.cpp diff --git a/src/network/kernel/qnetworkproxy_symbian.cpp b/src/network/kernel/qnetworkproxy_symbian.cpp new file mode 100644 index 0000000..7eba2c2 --- /dev/null +++ b/src/network/kernel/qnetworkproxy_symbian.cpp @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** 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 "qnetworkproxy.h" + +#ifndef QT_NO_NETWORKPROXY + +QT_BEGIN_NAMESPACE + +QList QNetworkProxyFactory::systemProxyForQuery(const QNetworkProxyQuery &) +{ + // TODO: Get the current QNetworkSession which has the Symbian RConnection we use + + // TODO: Get the proxy from that RConnection + + + // Default case: No network proxy found/needed + return QList() << QNetworkProxy::NoProxy; +} + +QT_END_NAMESPACE + +#endif -- cgit v0.12 From 0ce754850de6473bc0df1918d76a9b127b445260 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Tue, 7 Dec 2010 11:01:30 +0100 Subject: Some more qnetworkproxy_symbian information --- src/network/kernel/qnetworkproxy_symbian.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/network/kernel/qnetworkproxy_symbian.cpp b/src/network/kernel/qnetworkproxy_symbian.cpp index 7eba2c2..62266d1 100644 --- a/src/network/kernel/qnetworkproxy_symbian.cpp +++ b/src/network/kernel/qnetworkproxy_symbian.cpp @@ -48,9 +48,14 @@ QT_BEGIN_NAMESPACE QList QNetworkProxyFactory::systemProxyForQuery(const QNetworkProxyQuery &) { // TODO: Get the current QNetworkSession which has the Symbian RConnection we use + // I am wondering if we already have a connected QNetworkSession when the code + // is run that retrieves the proxy (for QNetworkAccessManager it's somewhere called + // from createRequest() which might be too early...) // TODO: Get the proxy from that RConnection + // See http://bugreports.qt.nokia.com/browse/QTBUG-13857 and http://bugreports.qt.nokia.com/browse/QTBUG-11016 + // and the mails we have received. // Default case: No network proxy found/needed return QList() << QNetworkProxy::NoProxy; -- cgit v0.12 From 7dce8f9b28288b95daf0e8fd1016b8b75bccc61c Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Tue, 7 Dec 2010 12:12:48 +0100 Subject: QTestLib: Wait a bit on Symbian at exit Reviewed-by: Shane Kearns --- src/testlib/qabstracttestlogger.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/testlib/qabstracttestlogger.cpp b/src/testlib/qabstracttestlogger.cpp index f7269d6..a23638e 100644 --- a/src/testlib/qabstracttestlogger.cpp +++ b/src/testlib/qabstracttestlogger.cpp @@ -104,8 +104,16 @@ void QAbstractTestLogger::startLogging() void QAbstractTestLogger::stopLogging() { QTEST_ASSERT(QTest::stream); - if (QTest::stream != stdout) + if (QTest::stream != stdout) { fclose(QTest::stream); + } else { +#ifdef Q_OS_SYMBIAN + // Convenience sleep for Symbian and TRK. Without this sleep depending on the timing the + // user would not see the complete output because it is still pending in any of the buffers + // before arriving via the USB port on the development PC + User::AfterHighRes(2*1000*1000); +#endif + } QTest::stream = 0; } -- cgit v0.12 From 2b60cdf7b0c17372cbeb32e3eac1e18c0baea0e4 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Tue, 7 Dec 2010 15:50:05 +0100 Subject: Move qnativesocketengine_symbian* to QSymbianSocketEngine Reviewed-By: Shane Kearns --- src/network/socket/qnativesocketengine_symbian.cpp | 806 --------------------- src/network/socket/qsymbiansocketengine.cpp | 806 +++++++++++++++++++++ src/network/socket/qsymbiansocketengine_p.h | 289 ++++++++ src/network/socket/socket.pri | 5 +- 4 files changed, 1099 insertions(+), 807 deletions(-) delete mode 100644 src/network/socket/qnativesocketengine_symbian.cpp create mode 100644 src/network/socket/qsymbiansocketengine.cpp create mode 100644 src/network/socket/qsymbiansocketengine_p.h diff --git a/src/network/socket/qnativesocketengine_symbian.cpp b/src/network/socket/qnativesocketengine_symbian.cpp deleted file mode 100644 index cfaee03..0000000 --- a/src/network/socket/qnativesocketengine_symbian.cpp +++ /dev/null @@ -1,806 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -//#define QNATIVESOCKETENGINE_DEBUG -#include "qnativesocketengine_p.h" -#include "private/qnet_unix_p.h" -#include "qiodevice.h" -#include "qhostaddress.h" -#include "qelapsedtimer.h" -#include "qvarlengtharray.h" -#include "qnetworkinterface.h" -#include -#include -#include -#ifndef QT_NO_IPV6IFNAME -#include -#endif - -#define QNATIVESOCKETENGINE_DEBUG - -#if defined QNATIVESOCKETENGINE_DEBUG -#include -#include -#endif - -QT_BEGIN_NAMESPACE - -#if defined QNATIVESOCKETENGINE_DEBUG - -/* - Returns a human readable representation of the first \a len - characters in \a data. -*/ -static QByteArray qt_prettyDebug(const char *data, int len, int maxSize) -{ - if (!data) return "(null)"; - QByteArray out; - for (int i = 0; i < len; ++i) { - char c = data[i]; - if (isprint(c)) { - out += c; - } else switch (c) { - case '\n': out += "\\n"; break; - case '\r': out += "\\r"; break; - case '\t': out += "\\t"; break; - default: - QString tmp; - tmp.sprintf("\\%o", c); - out += tmp.toLatin1(); - } - } - - if (len < maxSize) - out += "..."; - - return out; -} -#endif - -void QNativeSocketEnginePrivate::getPortAndAddress(const TInetAddr& a, quint16 *port, QHostAddress *addr) -{ -#if !defined(QT_NO_IPV6) - if (a.Family() == KAfInet6) { - Q_IPV6ADDR tmp; - memcpy(&tmp, a.Ip6Address().u.iAddr8, sizeof(tmp)); - if (addr) { - QHostAddress tmpAddress; - tmpAddress.setAddress(tmp); - *addr = tmpAddress; -#ifndef QT_NO_IPV6IFNAME - TPckgBuf query; - query().iSrcAddr = a; - TInt err = nativeSocket.GetOpt(KSoInetIfQueryBySrcAddr, KSolInetIfQuery, query); - if(!err) - addr->setScopeId(qt_TDesC2QString(query().iName)); - else -#endif - addr->setScopeId(QString::number(a.Scope())); - } - if (port) - *port = a.Port(); - return; - } -#endif - if (port) - *port = a.Port(); - if (addr) { - QHostAddress tmpAddress; - tmpAddress.setAddress(a.Address()); - *addr = tmpAddress; - } -} -/*! \internal - - Creates and returns a new socket descriptor of type \a socketType - and \a socketProtocol. Returns -1 on failure. -*/ -bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType, - QAbstractSocket::NetworkLayerProtocol socketProtocol) -{ -#ifndef QT_NO_IPV6 - TUint family = (socketProtocol == QAbstractSocket::IPv6Protocol) ? KAfInet6 : KAfInet; -#else - Q_UNUSED(socketProtocol); - TUint family = KAfInet; -#endif - TUint type = (socketType == QAbstractSocket::UdpSocket) ? KSockDatagram : KSockStream; - TUint protocol = (socketType == QAbstractSocket::UdpSocket) ? KProtocolInetUdp : KProtocolInetTcp; - TInt err = nativeSocket.Open(socketServer, family, type, protocol, connection); - - if (err != KErrNone) { - switch (err) { - case KErrNotSupported: - case KErrNotFound: - setError(QAbstractSocket::UnsupportedSocketOperationError, - ProtocolUnsupportedErrorString); - break; - case KErrNoMemory: - setError(QAbstractSocket::SocketResourceError, ResourceErrorString); - break; - case KErrPermissionDenied: - setError(QAbstractSocket::SocketAccessError, AccessErrorString); - break; - default: - break; - } - - return false; - } - // FIXME Set socket to nonblocking. While we are still a QNativeSocketEngine this is done already. - // Uncomment the following when we switch to QSymbianSocketEngine. - // setOption(NonBlockingSocketOption, 1) - - socketDescriptor = QSymbianSocketManager::instance().addSocket(nativeSocket); - return true; -} - -/* - Returns the value of the socket option \a opt. -*/ -int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) const -{ - Q_Q(const QNativeSocketEngine); - if (!q->isValid()) - return -1; - - TUint n; - TUint level = KSOLSocket; // default - - switch (opt) { - case QNativeSocketEngine::ReceiveBufferSocketOption: - n = KSORecvBuf; - break; - case QNativeSocketEngine::SendBufferSocketOption: - n = KSOSendBuf; - break; - case QNativeSocketEngine::NonBlockingSocketOption: - n = KSONonBlockingIO; - break; - case QNativeSocketEngine::BroadcastSocketOption: - return true; //symbian doesn't support or require this option - case QNativeSocketEngine::AddressReusable: - level = KSolInetIp; - n = KSoReuseAddr; - break; - case QNativeSocketEngine::BindExclusively: - return true; - case QNativeSocketEngine::ReceiveOutOfBandData: - level = KSolInetTcp; - n = KSoTcpOobInline; - break; - case QNativeSocketEngine::LowDelayOption: - level = KSolInetTcp; - n = KSoTcpNoDelay; - break; - case QNativeSocketEngine::KeepAliveOption: - level = KSolInetTcp; - n = KSoTcpKeepAlive; - break; - default: - return -1; - } - - int v = -1; - //GetOpt() is non const - TInt err = nativeSocket.GetOpt(n, level, v); - if (!err) - return v; - - return -1; -} - - -/* - Sets the socket option \a opt to \a v. -*/ -bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt, int v) -{ - Q_Q(QNativeSocketEngine); - if (!q->isValid()) - return false; - - int n = 0; - int level = SOL_SOCKET; // default - - switch (opt) { - case QNativeSocketEngine::ReceiveBufferSocketOption: - n = KSORecvBuf; - break; - case QNativeSocketEngine::SendBufferSocketOption: - n = KSOSendBuf; - break; - case QNativeSocketEngine::BroadcastSocketOption: - return true; - case QNativeSocketEngine::NonBlockingSocketOption: - n = KSONonBlockingIO; - break; - case QNativeSocketEngine::AddressReusable: - level = KSolInetIp; - n = KSoReuseAddr; - break; - case QNativeSocketEngine::BindExclusively: - return true; - case QNativeSocketEngine::ReceiveOutOfBandData: - level = KSolInetTcp; - n = KSoTcpOobInline; - break; - case QNativeSocketEngine::LowDelayOption: - level = KSolInetTcp; - n = KSoTcpNoDelay; - break; - case QNativeSocketEngine::KeepAliveOption: - level = KSolInetTcp; - n = KSoTcpKeepAlive; - break; - } - - return (KErrNone == nativeSocket.SetOpt(n, level, v)); -} - -void QNativeSocketEnginePrivate::setPortAndAddress(TInetAddr& nativeAddr, quint16 port, const QHostAddress &addr) -{ - nativeAddr.SetPort(port); -#if !defined(QT_NO_IPV6) - if (addr.protocol() == QAbstractSocket::IPv6Protocol) { -#ifndef QT_NO_IPV6IFNAME - TPckgBuf query; - query().iName = qt_QString2TPtrC(addr.scopeId()); - TInt err = nativeSocket.GetOpt(KSoInetIfQueryByName, KSolInetIfQuery, query); - if(!err) - nativeAddr.SetScope(query().iIndex); - else - nativeAddr.SetScope(0); -#else - nativeAddr.SetScope(addr.scopeId().toInt()); -#endif - Q_IPV6ADDR ip6 = addr.toIPv6Address(); - TIp6Addr v6addr; - memcpy(v6addr.u.iAddr8, ip6.c, 16); - nativeAddr.SetAddress(v6addr); - } else -#endif - if (addr.protocol() == QAbstractSocket::IPv4Protocol) { - nativeAddr.SetAddress(addr.toIPv4Address()); - } else { - qWarning("unsupported network protocol (%d)", addr.protocol()); - } -} - -bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16 port) -{ -#ifdef QNATIVESOCKETENGINE_DEBUG - qDebug("QNativeSocketEnginePrivate::nativeConnect() : %d ", socketDescriptor); -#endif - - TInetAddr nativeAddr; - setPortAndAddress(nativeAddr, port, addr); - //TODO: async connect with active object - from here to end of function is a mess - TRequestStatus status; - nativeSocket.Connect(nativeAddr, status); - User::WaitForRequest(status); - TInt err = status.Int(); - if (err) { - switch (err) { - case KErrCouldNotConnect: - setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString); - socketState = QAbstractSocket::UnconnectedState; - break; - case KErrTimedOut: - setError(QAbstractSocket::NetworkError, ConnectionTimeOutErrorString); - break; - case KErrHostUnreach: - setError(QAbstractSocket::NetworkError, HostUnreachableErrorString); - socketState = QAbstractSocket::UnconnectedState; - break; - case KErrNetUnreach: - setError(QAbstractSocket::NetworkError, NetworkUnreachableErrorString); - socketState = QAbstractSocket::UnconnectedState; - break; - case KErrInUse: - setError(QAbstractSocket::NetworkError, AddressInuseErrorString); - break; - case KErrPermissionDenied: - setError(QAbstractSocket::SocketAccessError, AccessErrorString); - socketState = QAbstractSocket::UnconnectedState; - break; - case KErrNotSupported: - case KErrBadDescriptor: - socketState = QAbstractSocket::UnconnectedState; - default: - break; - } - - if (socketState != QAbstractSocket::ConnectedState) { -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeConnect(%s, %i) == false (%s)", - addr.toString().toLatin1().constData(), port, - socketState == QAbstractSocket::ConnectingState - ? "Connection in progress" : socketErrorString.toLatin1().constData()); -#endif - return false; - } - } - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeConnect(%s, %i) == true", - addr.toString().toLatin1().constData(), port); -#endif - - socketState = QAbstractSocket::ConnectedState; - return true; -} - -bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, quint16 port) -{ - TInetAddr nativeAddr; - setPortAndAddress(nativeAddr, port, address); - - TInt err = nativeSocket.Bind(nativeAddr); - - if (err) { - switch(errno) { - case KErrInUse: - setError(QAbstractSocket::AddressInUseError, AddressInuseErrorString); - break; - case KErrPermissionDenied: - setError(QAbstractSocket::SocketAccessError, AddressProtectedErrorString); - break; - case KErrNotSupported: - setError(QAbstractSocket::UnsupportedSocketOperationError, OperationUnsupportedErrorString); - break; - default: - break; - } - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeBind(%s, %i) == false (%s)", - address.toString().toLatin1().constData(), port, socketErrorString.toLatin1().constData()); -#endif - - return false; - } - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeBind(%s, %i) == true", - address.toString().toLatin1().constData(), port); -#endif - socketState = QAbstractSocket::BoundState; - return true; -} - -bool QNativeSocketEnginePrivate::nativeListen(int backlog) -{ - TInt err = nativeSocket.Listen(backlog); - if (err) { - switch (errno) { - case KErrInUse: - setError(QAbstractSocket::AddressInUseError, - PortInuseErrorString); - break; - default: - break; - } - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeListen(%i) == false (%s)", - backlog, socketErrorString.toLatin1().constData()); -#endif - return false; - } - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeListen(%i) == true", backlog); -#endif - - socketState = QAbstractSocket::ListeningState; - return true; -} - -int QNativeSocketEnginePrivate::nativeAccept() -{ - RSocket blankSocket; - //TODO: this is unbelievably broken, needs to be properly async - blankSocket.Open(socketServer); - TRequestStatus status; - nativeSocket.Accept(blankSocket, status); - User::WaitForRequest(status); - if(status.Int()) { - qWarning("QNativeSocketEnginePrivate::nativeAccept() - error %d", status.Int()); - return 0; - } - // FIXME Qt Handle of new socket must be retrieved from QSymbianSocketManager - // and then returned. Not the SubSessionHandle! Also set the socket to nonblocking. - return blankSocket.SubSessionHandle(); -} - -qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const -{ - int nbytes = 0; - qint64 available = 0; - // FIXME is this the right thing also for UDP? - // What is expected for UDP, the length for the next packet I guess? - TInt err = nativeSocket.GetOpt(KSOReadBytesPending, KSOLSocket, nbytes); - if(err) - return 0; - available = (qint64) nbytes; - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeBytesAvailable() == %lli", available); -#endif - return available; -} - -bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const -{ - int nbytes; - TInt err = nativeSocket.GetOpt(KSOReadBytesPending,KSOLSocket, nbytes); - return err == KErrNone && nbytes > 0; - //TODO: this is pretty horrible too... -} - -qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const -{ - int nbytes; - TInt err = nativeSocket.GetOpt(KSOReadBytesPending,KSOLSocket, nbytes); - return qint64(nbytes-28); //TODO: why -28 (open C version had this)? - // Why = Could it be that this is about header lengths etc? if yes - // this could be pretty broken, especially for IPv6 -} - -qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxSize, - QHostAddress *address, quint16 *port) -{ - TPtr8 buffer((TUint8*)data, (int)maxSize); - TInetAddr addr; - TRequestStatus status; //TODO: OMG sync receive! - nativeSocket.RecvFrom(buffer, addr, 0, status); - User::WaitForRequest(status); - - if (status.Int()) { - setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString); - } else if (port || address) { - getPortAndAddress(addr, port, address); - } - -#if defined (QNATIVESOCKETENGINE_DEBUG) - int len = buffer.Length(); - qDebug("QNativeSocketEnginePrivate::nativeReceiveDatagram(%p \"%s\", %lli, %s, %i) == %lli", - data, qt_prettyDebug(data, qMin(len, ssize_t(16)), len).data(), maxSize, - address ? address->toString().toLatin1().constData() : "(nil)", - port ? *port : 0, (qint64) len); -#endif - - if (status.Int()) - return -1; - return qint64(buffer.Length()); -} - -qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 len, - const QHostAddress &host, quint16 port) -{ - TPtrC8 buffer((TUint8*)data, (int)len); - TInetAddr addr; - setPortAndAddress(addr, port, host); - TSockXfrLength sentBytes; - TRequestStatus status; //TODO: OMG sync send! - nativeSocket.SendTo(buffer, addr, 0, status, sentBytes); - User::WaitForRequest(status); - TInt err = status.Int(); - - if (err) { - switch (err) { - case KErrTooBig: - setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString); - break; - default: - setError(QAbstractSocket::NetworkError, SendDatagramErrorString); - } - } - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEngine::sendDatagram(%p \"%s\", %lli, \"%s\", %i) == %lli", data, - qt_prettyDebug(data, qMin(len, 16), len).data(), len, host.toString().toLatin1().constData(), - port, (qint64) sentBytes()); -#endif - - return qint64(sentBytes()); -} - -bool QNativeSocketEnginePrivate::fetchConnectionParameters() -{ - localPort = 0; - localAddress.clear(); - peerPort = 0; - peerAddress.clear(); - - if (socketDescriptor == -1) - return false; - - if (!nativeSocket.SubSessionHandle()) { - if (!QSymbianSocketManager::instance().lookupSocket(socketDescriptor, nativeSocket)) - return false; - } - - // Determine local address - TSockAddr addr; - nativeSocket.LocalName(addr); - getPortAndAddress(addr, &localPort, &localAddress); - - // Determine protocol family - switch (addr.Family()) { - case KAfInet: - socketProtocol = QAbstractSocket::IPv4Protocol; - break; -#if !defined (QT_NO_IPV6) - case KAfInet6: - socketProtocol = QAbstractSocket::IPv6Protocol; - break; -#endif - default: - socketProtocol = QAbstractSocket::UnknownNetworkLayerProtocol; - break; - } - - // Determine the remote address - nativeSocket.RemoteName(addr); - getPortAndAddress(addr, &peerPort, &peerAddress); - - // Determine the socket type (UDP/TCP) - TProtocolDesc protocol; - TInt err = nativeSocket.Info(protocol); - if (err) { - QAbstractSocket::UnknownSocketType; - } else { - switch (protocol.iProtocol) { - case KProtocolInetTcp: - socketType = QAbstractSocket::TcpSocket; - break; - case KProtocolInetUdp: - socketType = QAbstractSocket::UdpSocket; - break; - default: - socketType = QAbstractSocket::UnknownSocketType; - break; - } - } -#if defined (QNATIVESOCKETENGINE_DEBUG) - QString socketProtocolStr = "UnknownProtocol"; - if (socketProtocol == QAbstractSocket::IPv4Protocol) socketProtocolStr = "IPv4Protocol"; - else if (socketProtocol == QAbstractSocket::IPv6Protocol) socketProtocolStr = "IPv6Protocol"; - - QString socketTypeStr = "UnknownSocketType"; - if (socketType == QAbstractSocket::TcpSocket) socketTypeStr = "TcpSocket"; - else if (socketType == QAbstractSocket::UdpSocket) socketTypeStr = "UdpSocket"; - - qDebug("QNativeSocketEnginePrivate::fetchConnectionParameters() local == %s:%i," - " peer == %s:%i, socket == %s - %s", - localAddress.toString().toLatin1().constData(), localPort, - peerAddress.toString().toLatin1().constData(), peerPort,socketTypeStr.toLatin1().constData(), - socketProtocolStr.toLatin1().constData()); -#endif - return true; -} - -void QNativeSocketEnginePrivate::nativeClose() -{ -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEngine::nativeClose()"); -#endif - - //TODO: call nativeSocket.Shutdown(EImmediate) in some cases? - nativeSocket.Close(); - QSymbianSocketManager::instance().removeSocket(nativeSocket); -} - -qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len) -{ - Q_Q(QNativeSocketEngine); - TPtrC8 buffer((TUint8*)data, (int)len); - TSockXfrLength sentBytes; - TRequestStatus status; //TODO: OMG sync send! - nativeSocket.Send(buffer, 0, status, sentBytes); - User::WaitForRequest(status); - TInt err = status.Int(); - - if (err) { - switch (err) { - case KErrDisconnected: - sentBytes = -1; - setError(QAbstractSocket::RemoteHostClosedError, RemoteHostClosedErrorString); - q->close(); - break; - case KErrTooBig: - setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString); - break; - case KErrWouldBlock: - sentBytes = 0; - default: - setError(QAbstractSocket::NetworkError, SendDatagramErrorString); - } - } - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeWrite(%p \"%s\", %llu) == %i", - data, qt_prettyDebug(data, qMin((int) len, 16), - (int) len).data(), len, (int) sentBytes()); -#endif - - return qint64(sentBytes()); -} -/* -*/ -qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize) -{ - Q_Q(QNativeSocketEngine); - if (!q->isValid()) { - qWarning("QNativeSocketEngine::nativeRead: Invalid socket"); - return -1; - } - - TPtr8 buffer((TUint8*)data, (int)maxSize); - TSockXfrLength received = 0; - TRequestStatus status; //TODO: OMG sync receive! - nativeSocket.RecvOneOrMore(buffer, 0, status, received); - User::WaitForRequest(status); - TInt err = status.Int(); - int r = received(); - - if (err) { - switch(err) { - case KErrWouldBlock: - // No data was available for reading - r = -2; - break; - case KErrDisconnected: - r = 0; - break; - default: - r = -1; - //error string is now set in read(), not here in nativeRead() - break; - } - } - -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeRead(%p \"%s\", %llu) == %i", - data, qt_prettyDebug(data, qMin(r, ssize_t(16)), r).data(), - maxSize, r); -#endif - - return qint64(r); -} - -int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const -{ - bool readyRead = false; - bool readyWrite = false; - if (selectForRead) - return nativeSelect(timeout, true, false, &readyRead, &readyWrite); - else - return nativeSelect(timeout, false, true, &readyRead, &readyWrite); -} - -/*! - \internal - \param timeout timeout in milliseconds - \param checkRead caller is interested if the socket is ready to read - \param checkWrite caller is interested if the socket is ready for write - \param selectForRead (out) should set to true if ready to read - \param selectForWrite (out) should set to true if ready to write - \return 0 on timeout, >0 on success, <0 on error - */ -int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool checkWrite, - bool *selectForRead, bool *selectForWrite) const -{ - //TODO: implement - //as above, but checking both read and write status at the same time - if (!selectTimer.Handle()) - qt_symbian_throwIfError(selectTimer.CreateLocal()); - TRequestStatus timerStat; - selectTimer.HighRes(timerStat, timeout * 1000); - TRequestStatus* readStat = 0; - TRequestStatus* writeStat = 0; - TRequestStatus* array[3]; - array[0] = &timerStat; - int count = 1; - if (checkRead) { - //TODO: get from read AO - //readStat = ? - array[count++] = readStat; - } - if (checkWrite) { - //TODO: get from write AO - //writeStat = ? - array[count++] = writeStat; - } - // TODO: for selecting, we can use getOpt(KSOSelectPoll) to get the select result - // and KIOCtlSelect for the selecting. - - User::WaitForNRequest(array, count); - //IMPORTANT - WaitForNRequest only decrements the thread semaphore once, although more than one status may have completed. - if (timerStat.Int() != KRequestPending) { - //timed out - return 0; - } - selectTimer.Cancel(); - User::WaitForRequest(timerStat); - - if(readStat && readStat->Int() != KRequestPending) { - Q_ASSERT(checkRead && selectForRead); - //TODO: cancel the AO, but call its RunL anyway? looking for an UnsetActive() - *selectForRead = true; - } - if(writeStat && writeStat->Int() != KRequestPending) { - Q_ASSERT(checkWrite && selectForWrite); - //TODO: cancel the AO, but call its RunL anyway? looking for an UnsetActive() - *selectForWrite = true; - } - return 1; -} - -bool QNativeSocketEnginePrivate::nativeJoinMulticastGroup(const QHostAddress &groupAddress, - const QNetworkInterface &iface) -{ - //TODO - return false; -} - -bool QNativeSocketEnginePrivate::nativeLeaveMulticastGroup(const QHostAddress &groupAddress, - const QNetworkInterface &iface) -{ - //TODO - return false; -} - -QNetworkInterface QNativeSocketEnginePrivate::nativeMulticastInterface() const -{ - //TODO - return QNetworkInterface(); -} - -bool QNativeSocketEnginePrivate::nativeSetMulticastInterface(const QNetworkInterface &iface) -{ - //TODO - return false; -} - -QT_END_NAMESPACE diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp new file mode 100644 index 0000000..cfaee03 --- /dev/null +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -0,0 +1,806 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +//#define QNATIVESOCKETENGINE_DEBUG +#include "qnativesocketengine_p.h" +#include "private/qnet_unix_p.h" +#include "qiodevice.h" +#include "qhostaddress.h" +#include "qelapsedtimer.h" +#include "qvarlengtharray.h" +#include "qnetworkinterface.h" +#include +#include +#include +#ifndef QT_NO_IPV6IFNAME +#include +#endif + +#define QNATIVESOCKETENGINE_DEBUG + +#if defined QNATIVESOCKETENGINE_DEBUG +#include +#include +#endif + +QT_BEGIN_NAMESPACE + +#if defined QNATIVESOCKETENGINE_DEBUG + +/* + Returns a human readable representation of the first \a len + characters in \a data. +*/ +static QByteArray qt_prettyDebug(const char *data, int len, int maxSize) +{ + if (!data) return "(null)"; + QByteArray out; + for (int i = 0; i < len; ++i) { + char c = data[i]; + if (isprint(c)) { + out += c; + } else switch (c) { + case '\n': out += "\\n"; break; + case '\r': out += "\\r"; break; + case '\t': out += "\\t"; break; + default: + QString tmp; + tmp.sprintf("\\%o", c); + out += tmp.toLatin1(); + } + } + + if (len < maxSize) + out += "..."; + + return out; +} +#endif + +void QNativeSocketEnginePrivate::getPortAndAddress(const TInetAddr& a, quint16 *port, QHostAddress *addr) +{ +#if !defined(QT_NO_IPV6) + if (a.Family() == KAfInet6) { + Q_IPV6ADDR tmp; + memcpy(&tmp, a.Ip6Address().u.iAddr8, sizeof(tmp)); + if (addr) { + QHostAddress tmpAddress; + tmpAddress.setAddress(tmp); + *addr = tmpAddress; +#ifndef QT_NO_IPV6IFNAME + TPckgBuf query; + query().iSrcAddr = a; + TInt err = nativeSocket.GetOpt(KSoInetIfQueryBySrcAddr, KSolInetIfQuery, query); + if(!err) + addr->setScopeId(qt_TDesC2QString(query().iName)); + else +#endif + addr->setScopeId(QString::number(a.Scope())); + } + if (port) + *port = a.Port(); + return; + } +#endif + if (port) + *port = a.Port(); + if (addr) { + QHostAddress tmpAddress; + tmpAddress.setAddress(a.Address()); + *addr = tmpAddress; + } +} +/*! \internal + + Creates and returns a new socket descriptor of type \a socketType + and \a socketProtocol. Returns -1 on failure. +*/ +bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType, + QAbstractSocket::NetworkLayerProtocol socketProtocol) +{ +#ifndef QT_NO_IPV6 + TUint family = (socketProtocol == QAbstractSocket::IPv6Protocol) ? KAfInet6 : KAfInet; +#else + Q_UNUSED(socketProtocol); + TUint family = KAfInet; +#endif + TUint type = (socketType == QAbstractSocket::UdpSocket) ? KSockDatagram : KSockStream; + TUint protocol = (socketType == QAbstractSocket::UdpSocket) ? KProtocolInetUdp : KProtocolInetTcp; + TInt err = nativeSocket.Open(socketServer, family, type, protocol, connection); + + if (err != KErrNone) { + switch (err) { + case KErrNotSupported: + case KErrNotFound: + setError(QAbstractSocket::UnsupportedSocketOperationError, + ProtocolUnsupportedErrorString); + break; + case KErrNoMemory: + setError(QAbstractSocket::SocketResourceError, ResourceErrorString); + break; + case KErrPermissionDenied: + setError(QAbstractSocket::SocketAccessError, AccessErrorString); + break; + default: + break; + } + + return false; + } + // FIXME Set socket to nonblocking. While we are still a QNativeSocketEngine this is done already. + // Uncomment the following when we switch to QSymbianSocketEngine. + // setOption(NonBlockingSocketOption, 1) + + socketDescriptor = QSymbianSocketManager::instance().addSocket(nativeSocket); + return true; +} + +/* + Returns the value of the socket option \a opt. +*/ +int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) const +{ + Q_Q(const QNativeSocketEngine); + if (!q->isValid()) + return -1; + + TUint n; + TUint level = KSOLSocket; // default + + switch (opt) { + case QNativeSocketEngine::ReceiveBufferSocketOption: + n = KSORecvBuf; + break; + case QNativeSocketEngine::SendBufferSocketOption: + n = KSOSendBuf; + break; + case QNativeSocketEngine::NonBlockingSocketOption: + n = KSONonBlockingIO; + break; + case QNativeSocketEngine::BroadcastSocketOption: + return true; //symbian doesn't support or require this option + case QNativeSocketEngine::AddressReusable: + level = KSolInetIp; + n = KSoReuseAddr; + break; + case QNativeSocketEngine::BindExclusively: + return true; + case QNativeSocketEngine::ReceiveOutOfBandData: + level = KSolInetTcp; + n = KSoTcpOobInline; + break; + case QNativeSocketEngine::LowDelayOption: + level = KSolInetTcp; + n = KSoTcpNoDelay; + break; + case QNativeSocketEngine::KeepAliveOption: + level = KSolInetTcp; + n = KSoTcpKeepAlive; + break; + default: + return -1; + } + + int v = -1; + //GetOpt() is non const + TInt err = nativeSocket.GetOpt(n, level, v); + if (!err) + return v; + + return -1; +} + + +/* + Sets the socket option \a opt to \a v. +*/ +bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt, int v) +{ + Q_Q(QNativeSocketEngine); + if (!q->isValid()) + return false; + + int n = 0; + int level = SOL_SOCKET; // default + + switch (opt) { + case QNativeSocketEngine::ReceiveBufferSocketOption: + n = KSORecvBuf; + break; + case QNativeSocketEngine::SendBufferSocketOption: + n = KSOSendBuf; + break; + case QNativeSocketEngine::BroadcastSocketOption: + return true; + case QNativeSocketEngine::NonBlockingSocketOption: + n = KSONonBlockingIO; + break; + case QNativeSocketEngine::AddressReusable: + level = KSolInetIp; + n = KSoReuseAddr; + break; + case QNativeSocketEngine::BindExclusively: + return true; + case QNativeSocketEngine::ReceiveOutOfBandData: + level = KSolInetTcp; + n = KSoTcpOobInline; + break; + case QNativeSocketEngine::LowDelayOption: + level = KSolInetTcp; + n = KSoTcpNoDelay; + break; + case QNativeSocketEngine::KeepAliveOption: + level = KSolInetTcp; + n = KSoTcpKeepAlive; + break; + } + + return (KErrNone == nativeSocket.SetOpt(n, level, v)); +} + +void QNativeSocketEnginePrivate::setPortAndAddress(TInetAddr& nativeAddr, quint16 port, const QHostAddress &addr) +{ + nativeAddr.SetPort(port); +#if !defined(QT_NO_IPV6) + if (addr.protocol() == QAbstractSocket::IPv6Protocol) { +#ifndef QT_NO_IPV6IFNAME + TPckgBuf query; + query().iName = qt_QString2TPtrC(addr.scopeId()); + TInt err = nativeSocket.GetOpt(KSoInetIfQueryByName, KSolInetIfQuery, query); + if(!err) + nativeAddr.SetScope(query().iIndex); + else + nativeAddr.SetScope(0); +#else + nativeAddr.SetScope(addr.scopeId().toInt()); +#endif + Q_IPV6ADDR ip6 = addr.toIPv6Address(); + TIp6Addr v6addr; + memcpy(v6addr.u.iAddr8, ip6.c, 16); + nativeAddr.SetAddress(v6addr); + } else +#endif + if (addr.protocol() == QAbstractSocket::IPv4Protocol) { + nativeAddr.SetAddress(addr.toIPv4Address()); + } else { + qWarning("unsupported network protocol (%d)", addr.protocol()); + } +} + +bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16 port) +{ +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug("QNativeSocketEnginePrivate::nativeConnect() : %d ", socketDescriptor); +#endif + + TInetAddr nativeAddr; + setPortAndAddress(nativeAddr, port, addr); + //TODO: async connect with active object - from here to end of function is a mess + TRequestStatus status; + nativeSocket.Connect(nativeAddr, status); + User::WaitForRequest(status); + TInt err = status.Int(); + if (err) { + switch (err) { + case KErrCouldNotConnect: + setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString); + socketState = QAbstractSocket::UnconnectedState; + break; + case KErrTimedOut: + setError(QAbstractSocket::NetworkError, ConnectionTimeOutErrorString); + break; + case KErrHostUnreach: + setError(QAbstractSocket::NetworkError, HostUnreachableErrorString); + socketState = QAbstractSocket::UnconnectedState; + break; + case KErrNetUnreach: + setError(QAbstractSocket::NetworkError, NetworkUnreachableErrorString); + socketState = QAbstractSocket::UnconnectedState; + break; + case KErrInUse: + setError(QAbstractSocket::NetworkError, AddressInuseErrorString); + break; + case KErrPermissionDenied: + setError(QAbstractSocket::SocketAccessError, AccessErrorString); + socketState = QAbstractSocket::UnconnectedState; + break; + case KErrNotSupported: + case KErrBadDescriptor: + socketState = QAbstractSocket::UnconnectedState; + default: + break; + } + + if (socketState != QAbstractSocket::ConnectedState) { +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEnginePrivate::nativeConnect(%s, %i) == false (%s)", + addr.toString().toLatin1().constData(), port, + socketState == QAbstractSocket::ConnectingState + ? "Connection in progress" : socketErrorString.toLatin1().constData()); +#endif + return false; + } + } + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEnginePrivate::nativeConnect(%s, %i) == true", + addr.toString().toLatin1().constData(), port); +#endif + + socketState = QAbstractSocket::ConnectedState; + return true; +} + +bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, quint16 port) +{ + TInetAddr nativeAddr; + setPortAndAddress(nativeAddr, port, address); + + TInt err = nativeSocket.Bind(nativeAddr); + + if (err) { + switch(errno) { + case KErrInUse: + setError(QAbstractSocket::AddressInUseError, AddressInuseErrorString); + break; + case KErrPermissionDenied: + setError(QAbstractSocket::SocketAccessError, AddressProtectedErrorString); + break; + case KErrNotSupported: + setError(QAbstractSocket::UnsupportedSocketOperationError, OperationUnsupportedErrorString); + break; + default: + break; + } + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEnginePrivate::nativeBind(%s, %i) == false (%s)", + address.toString().toLatin1().constData(), port, socketErrorString.toLatin1().constData()); +#endif + + return false; + } + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEnginePrivate::nativeBind(%s, %i) == true", + address.toString().toLatin1().constData(), port); +#endif + socketState = QAbstractSocket::BoundState; + return true; +} + +bool QNativeSocketEnginePrivate::nativeListen(int backlog) +{ + TInt err = nativeSocket.Listen(backlog); + if (err) { + switch (errno) { + case KErrInUse: + setError(QAbstractSocket::AddressInUseError, + PortInuseErrorString); + break; + default: + break; + } + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEnginePrivate::nativeListen(%i) == false (%s)", + backlog, socketErrorString.toLatin1().constData()); +#endif + return false; + } + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEnginePrivate::nativeListen(%i) == true", backlog); +#endif + + socketState = QAbstractSocket::ListeningState; + return true; +} + +int QNativeSocketEnginePrivate::nativeAccept() +{ + RSocket blankSocket; + //TODO: this is unbelievably broken, needs to be properly async + blankSocket.Open(socketServer); + TRequestStatus status; + nativeSocket.Accept(blankSocket, status); + User::WaitForRequest(status); + if(status.Int()) { + qWarning("QNativeSocketEnginePrivate::nativeAccept() - error %d", status.Int()); + return 0; + } + // FIXME Qt Handle of new socket must be retrieved from QSymbianSocketManager + // and then returned. Not the SubSessionHandle! Also set the socket to nonblocking. + return blankSocket.SubSessionHandle(); +} + +qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const +{ + int nbytes = 0; + qint64 available = 0; + // FIXME is this the right thing also for UDP? + // What is expected for UDP, the length for the next packet I guess? + TInt err = nativeSocket.GetOpt(KSOReadBytesPending, KSOLSocket, nbytes); + if(err) + return 0; + available = (qint64) nbytes; + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEnginePrivate::nativeBytesAvailable() == %lli", available); +#endif + return available; +} + +bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const +{ + int nbytes; + TInt err = nativeSocket.GetOpt(KSOReadBytesPending,KSOLSocket, nbytes); + return err == KErrNone && nbytes > 0; + //TODO: this is pretty horrible too... +} + +qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const +{ + int nbytes; + TInt err = nativeSocket.GetOpt(KSOReadBytesPending,KSOLSocket, nbytes); + return qint64(nbytes-28); //TODO: why -28 (open C version had this)? + // Why = Could it be that this is about header lengths etc? if yes + // this could be pretty broken, especially for IPv6 +} + +qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxSize, + QHostAddress *address, quint16 *port) +{ + TPtr8 buffer((TUint8*)data, (int)maxSize); + TInetAddr addr; + TRequestStatus status; //TODO: OMG sync receive! + nativeSocket.RecvFrom(buffer, addr, 0, status); + User::WaitForRequest(status); + + if (status.Int()) { + setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString); + } else if (port || address) { + getPortAndAddress(addr, port, address); + } + +#if defined (QNATIVESOCKETENGINE_DEBUG) + int len = buffer.Length(); + qDebug("QNativeSocketEnginePrivate::nativeReceiveDatagram(%p \"%s\", %lli, %s, %i) == %lli", + data, qt_prettyDebug(data, qMin(len, ssize_t(16)), len).data(), maxSize, + address ? address->toString().toLatin1().constData() : "(nil)", + port ? *port : 0, (qint64) len); +#endif + + if (status.Int()) + return -1; + return qint64(buffer.Length()); +} + +qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 len, + const QHostAddress &host, quint16 port) +{ + TPtrC8 buffer((TUint8*)data, (int)len); + TInetAddr addr; + setPortAndAddress(addr, port, host); + TSockXfrLength sentBytes; + TRequestStatus status; //TODO: OMG sync send! + nativeSocket.SendTo(buffer, addr, 0, status, sentBytes); + User::WaitForRequest(status); + TInt err = status.Int(); + + if (err) { + switch (err) { + case KErrTooBig: + setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString); + break; + default: + setError(QAbstractSocket::NetworkError, SendDatagramErrorString); + } + } + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEngine::sendDatagram(%p \"%s\", %lli, \"%s\", %i) == %lli", data, + qt_prettyDebug(data, qMin(len, 16), len).data(), len, host.toString().toLatin1().constData(), + port, (qint64) sentBytes()); +#endif + + return qint64(sentBytes()); +} + +bool QNativeSocketEnginePrivate::fetchConnectionParameters() +{ + localPort = 0; + localAddress.clear(); + peerPort = 0; + peerAddress.clear(); + + if (socketDescriptor == -1) + return false; + + if (!nativeSocket.SubSessionHandle()) { + if (!QSymbianSocketManager::instance().lookupSocket(socketDescriptor, nativeSocket)) + return false; + } + + // Determine local address + TSockAddr addr; + nativeSocket.LocalName(addr); + getPortAndAddress(addr, &localPort, &localAddress); + + // Determine protocol family + switch (addr.Family()) { + case KAfInet: + socketProtocol = QAbstractSocket::IPv4Protocol; + break; +#if !defined (QT_NO_IPV6) + case KAfInet6: + socketProtocol = QAbstractSocket::IPv6Protocol; + break; +#endif + default: + socketProtocol = QAbstractSocket::UnknownNetworkLayerProtocol; + break; + } + + // Determine the remote address + nativeSocket.RemoteName(addr); + getPortAndAddress(addr, &peerPort, &peerAddress); + + // Determine the socket type (UDP/TCP) + TProtocolDesc protocol; + TInt err = nativeSocket.Info(protocol); + if (err) { + QAbstractSocket::UnknownSocketType; + } else { + switch (protocol.iProtocol) { + case KProtocolInetTcp: + socketType = QAbstractSocket::TcpSocket; + break; + case KProtocolInetUdp: + socketType = QAbstractSocket::UdpSocket; + break; + default: + socketType = QAbstractSocket::UnknownSocketType; + break; + } + } +#if defined (QNATIVESOCKETENGINE_DEBUG) + QString socketProtocolStr = "UnknownProtocol"; + if (socketProtocol == QAbstractSocket::IPv4Protocol) socketProtocolStr = "IPv4Protocol"; + else if (socketProtocol == QAbstractSocket::IPv6Protocol) socketProtocolStr = "IPv6Protocol"; + + QString socketTypeStr = "UnknownSocketType"; + if (socketType == QAbstractSocket::TcpSocket) socketTypeStr = "TcpSocket"; + else if (socketType == QAbstractSocket::UdpSocket) socketTypeStr = "UdpSocket"; + + qDebug("QNativeSocketEnginePrivate::fetchConnectionParameters() local == %s:%i," + " peer == %s:%i, socket == %s - %s", + localAddress.toString().toLatin1().constData(), localPort, + peerAddress.toString().toLatin1().constData(), peerPort,socketTypeStr.toLatin1().constData(), + socketProtocolStr.toLatin1().constData()); +#endif + return true; +} + +void QNativeSocketEnginePrivate::nativeClose() +{ +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEngine::nativeClose()"); +#endif + + //TODO: call nativeSocket.Shutdown(EImmediate) in some cases? + nativeSocket.Close(); + QSymbianSocketManager::instance().removeSocket(nativeSocket); +} + +qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len) +{ + Q_Q(QNativeSocketEngine); + TPtrC8 buffer((TUint8*)data, (int)len); + TSockXfrLength sentBytes; + TRequestStatus status; //TODO: OMG sync send! + nativeSocket.Send(buffer, 0, status, sentBytes); + User::WaitForRequest(status); + TInt err = status.Int(); + + if (err) { + switch (err) { + case KErrDisconnected: + sentBytes = -1; + setError(QAbstractSocket::RemoteHostClosedError, RemoteHostClosedErrorString); + q->close(); + break; + case KErrTooBig: + setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString); + break; + case KErrWouldBlock: + sentBytes = 0; + default: + setError(QAbstractSocket::NetworkError, SendDatagramErrorString); + } + } + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEnginePrivate::nativeWrite(%p \"%s\", %llu) == %i", + data, qt_prettyDebug(data, qMin((int) len, 16), + (int) len).data(), len, (int) sentBytes()); +#endif + + return qint64(sentBytes()); +} +/* +*/ +qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize) +{ + Q_Q(QNativeSocketEngine); + if (!q->isValid()) { + qWarning("QNativeSocketEngine::nativeRead: Invalid socket"); + return -1; + } + + TPtr8 buffer((TUint8*)data, (int)maxSize); + TSockXfrLength received = 0; + TRequestStatus status; //TODO: OMG sync receive! + nativeSocket.RecvOneOrMore(buffer, 0, status, received); + User::WaitForRequest(status); + TInt err = status.Int(); + int r = received(); + + if (err) { + switch(err) { + case KErrWouldBlock: + // No data was available for reading + r = -2; + break; + case KErrDisconnected: + r = 0; + break; + default: + r = -1; + //error string is now set in read(), not here in nativeRead() + break; + } + } + +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEnginePrivate::nativeRead(%p \"%s\", %llu) == %i", + data, qt_prettyDebug(data, qMin(r, ssize_t(16)), r).data(), + maxSize, r); +#endif + + return qint64(r); +} + +int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const +{ + bool readyRead = false; + bool readyWrite = false; + if (selectForRead) + return nativeSelect(timeout, true, false, &readyRead, &readyWrite); + else + return nativeSelect(timeout, false, true, &readyRead, &readyWrite); +} + +/*! + \internal + \param timeout timeout in milliseconds + \param checkRead caller is interested if the socket is ready to read + \param checkWrite caller is interested if the socket is ready for write + \param selectForRead (out) should set to true if ready to read + \param selectForWrite (out) should set to true if ready to write + \return 0 on timeout, >0 on success, <0 on error + */ +int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool checkWrite, + bool *selectForRead, bool *selectForWrite) const +{ + //TODO: implement + //as above, but checking both read and write status at the same time + if (!selectTimer.Handle()) + qt_symbian_throwIfError(selectTimer.CreateLocal()); + TRequestStatus timerStat; + selectTimer.HighRes(timerStat, timeout * 1000); + TRequestStatus* readStat = 0; + TRequestStatus* writeStat = 0; + TRequestStatus* array[3]; + array[0] = &timerStat; + int count = 1; + if (checkRead) { + //TODO: get from read AO + //readStat = ? + array[count++] = readStat; + } + if (checkWrite) { + //TODO: get from write AO + //writeStat = ? + array[count++] = writeStat; + } + // TODO: for selecting, we can use getOpt(KSOSelectPoll) to get the select result + // and KIOCtlSelect for the selecting. + + User::WaitForNRequest(array, count); + //IMPORTANT - WaitForNRequest only decrements the thread semaphore once, although more than one status may have completed. + if (timerStat.Int() != KRequestPending) { + //timed out + return 0; + } + selectTimer.Cancel(); + User::WaitForRequest(timerStat); + + if(readStat && readStat->Int() != KRequestPending) { + Q_ASSERT(checkRead && selectForRead); + //TODO: cancel the AO, but call its RunL anyway? looking for an UnsetActive() + *selectForRead = true; + } + if(writeStat && writeStat->Int() != KRequestPending) { + Q_ASSERT(checkWrite && selectForWrite); + //TODO: cancel the AO, but call its RunL anyway? looking for an UnsetActive() + *selectForWrite = true; + } + return 1; +} + +bool QNativeSocketEnginePrivate::nativeJoinMulticastGroup(const QHostAddress &groupAddress, + const QNetworkInterface &iface) +{ + //TODO + return false; +} + +bool QNativeSocketEnginePrivate::nativeLeaveMulticastGroup(const QHostAddress &groupAddress, + const QNetworkInterface &iface) +{ + //TODO + return false; +} + +QNetworkInterface QNativeSocketEnginePrivate::nativeMulticastInterface() const +{ + //TODO + return QNetworkInterface(); +} + +bool QNativeSocketEnginePrivate::nativeSetMulticastInterface(const QNetworkInterface &iface) +{ + //TODO + return false; +} + +QT_END_NAMESPACE diff --git a/src/network/socket/qsymbiansocketengine_p.h b/src/network/socket/qsymbiansocketengine_p.h new file mode 100644 index 0000000..c017065 --- /dev/null +++ b/src/network/socket/qsymbiansocketengine_p.h @@ -0,0 +1,289 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QNATIVESOCKETENGINE_P_H +#define QNATIVESOCKETENGINE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of the QLibrary class. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// +#include "QtNetwork/qhostaddress.h" +#include "private/qabstractsocketengine_p.h" +#ifndef Q_OS_WIN +# include "qplatformdefs.h" +#else +# include +#endif + +#ifdef Q_OS_SYMBIAN +#include +#include +#include +#include +#endif + +QT_BEGIN_NAMESPACE + +// Use our own defines and structs which we know are correct +# define QT_SS_MAXSIZE 128 +# define QT_SS_ALIGNSIZE (sizeof(qint64)) +# define QT_SS_PAD1SIZE (QT_SS_ALIGNSIZE - sizeof (short)) +# define QT_SS_PAD2SIZE (QT_SS_MAXSIZE - (sizeof (short) + QT_SS_PAD1SIZE + QT_SS_ALIGNSIZE)) +struct qt_sockaddr_storage { + short ss_family; + char __ss_pad1[QT_SS_PAD1SIZE]; + qint64 __ss_align; + char __ss_pad2[QT_SS_PAD2SIZE]; +}; + +// sockaddr_in6 size changed between old and new SDK +// Only the new version is the correct one, so always +// use this structure. +struct qt_in6_addr { + quint8 qt_s6_addr[16]; +}; +struct qt_sockaddr_in6 { + short sin6_family; /* AF_INET6 */ + quint16 sin6_port; /* Transport level port number */ + quint32 sin6_flowinfo; /* IPv6 flow information */ + struct qt_in6_addr sin6_addr; /* IPv6 address */ + quint32 sin6_scope_id; /* set of interfaces for a scope */ +}; + +union qt_sockaddr { + sockaddr a; + sockaddr_in a4; + qt_sockaddr_in6 a6; + qt_sockaddr_storage storage; +}; + +class QNativeSocketEnginePrivate; +class QNetworkInterface; + +class Q_AUTOTEST_EXPORT QNativeSocketEngine : public QAbstractSocketEngine +{ + Q_OBJECT +public: + QNativeSocketEngine(QObject *parent = 0); + ~QNativeSocketEngine(); + + bool initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol = QAbstractSocket::IPv4Protocol); + bool initialize(int socketDescriptor, QAbstractSocket::SocketState socketState = QAbstractSocket::ConnectedState); + + int socketDescriptor() const; + + bool isValid() const; + + bool connectToHost(const QHostAddress &address, quint16 port); + bool connectToHostByName(const QString &name, quint16 port); + bool bind(const QHostAddress &address, quint16 port); + bool listen(); + int accept(); + void close(); + + bool joinMulticastGroup(const QHostAddress &groupAddress, + const QNetworkInterface &iface); + bool leaveMulticastGroup(const QHostAddress &groupAddress, + const QNetworkInterface &iface); + QNetworkInterface multicastInterface() const; + bool setMulticastInterface(const QNetworkInterface &iface); + + qint64 bytesAvailable() const; + + qint64 read(char *data, qint64 maxlen); + qint64 write(const char *data, qint64 len); + + qint64 readDatagram(char *data, qint64 maxlen, QHostAddress *addr = 0, + quint16 *port = 0); + qint64 writeDatagram(const char *data, qint64 len, const QHostAddress &addr, + quint16 port); + bool hasPendingDatagrams() const; + qint64 pendingDatagramSize() const; + + qint64 bytesToWrite() const; + + qint64 receiveBufferSize() const; + void setReceiveBufferSize(qint64 bufferSize); + + qint64 sendBufferSize() const; + void setSendBufferSize(qint64 bufferSize); + + int option(SocketOption option) const; + bool setOption(SocketOption option, int value); + + bool waitForRead(int msecs = 30000, bool *timedOut = 0); + bool waitForWrite(int msecs = 30000, bool *timedOut = 0); + bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite, + bool checkRead, bool checkWrite, + int msecs = 30000, bool *timedOut = 0); + + bool isReadNotificationEnabled() const; + void setReadNotificationEnabled(bool enable); + bool isWriteNotificationEnabled() const; + void setWriteNotificationEnabled(bool enable); + bool isExceptionNotificationEnabled() const; + void setExceptionNotificationEnabled(bool enable); + +public Q_SLOTS: + // non-virtual override; + void connectionNotification(); + +private: + Q_DECLARE_PRIVATE(QNativeSocketEngine) + Q_DISABLE_COPY(QNativeSocketEngine) +}; + +#ifdef Q_OS_WIN +class QWindowsSockInit +{ +public: + QWindowsSockInit(); + ~QWindowsSockInit(); + int version; +}; +#endif + +class QSocketNotifier; + +class QNativeSocketEnginePrivate : public QAbstractSocketEnginePrivate +{ + Q_DECLARE_PUBLIC(QNativeSocketEngine) +public: + QNativeSocketEnginePrivate(); + ~QNativeSocketEnginePrivate(); + + int socketDescriptor; +#ifdef Q_OS_SYMBIAN + mutable RSocket nativeSocket; + RSocketServ& socketServer; + RConnection connection; //TODO: shared ref + mutable RTimer selectTimer; +#endif + + QSocketNotifier *readNotifier, *writeNotifier, *exceptNotifier; + +#ifdef Q_OS_WIN + QWindowsSockInit winSock; +#endif + + enum ErrorString { + NonBlockingInitFailedErrorString, + BroadcastingInitFailedErrorString, + NoIpV6ErrorString, + RemoteHostClosedErrorString, + TimeOutErrorString, + ResourceErrorString, + OperationUnsupportedErrorString, + ProtocolUnsupportedErrorString, + InvalidSocketErrorString, + HostUnreachableErrorString, + NetworkUnreachableErrorString, + AccessErrorString, + ConnectionTimeOutErrorString, + ConnectionRefusedErrorString, + AddressInuseErrorString, + AddressNotAvailableErrorString, + AddressProtectedErrorString, + DatagramTooLargeErrorString, + SendDatagramErrorString, + ReceiveDatagramErrorString, + WriteErrorString, + ReadErrorString, + PortInuseErrorString, + NotSocketErrorString, + InvalidProxyTypeString, + + UnknownSocketErrorString = -1 + }; + +#ifdef Q_OS_SYMBIAN + void getPortAndAddress(const TInetAddr& a, quint16 *port, QHostAddress *addr); + void setPortAndAddress(TInetAddr& nativeAddr, quint16 port, const QHostAddress &addr); + void setError(TInt symbianError); +#endif + void setError(QAbstractSocket::SocketError error, ErrorString errorString) const; + + // native functions + int option(QNativeSocketEngine::SocketOption option) const; + bool setOption(QNativeSocketEngine::SocketOption option, int value); + + bool createNewSocket(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol); + + bool nativeConnect(const QHostAddress &address, quint16 port); + bool nativeBind(const QHostAddress &address, quint16 port); + bool nativeListen(int backlog); + int nativeAccept(); + bool nativeJoinMulticastGroup(const QHostAddress &groupAddress, + const QNetworkInterface &iface); + bool nativeLeaveMulticastGroup(const QHostAddress &groupAddress, + const QNetworkInterface &iface); + QNetworkInterface nativeMulticastInterface() const; + bool nativeSetMulticastInterface(const QNetworkInterface &iface); + qint64 nativeBytesAvailable() const; + + bool nativeHasPendingDatagrams() const; + qint64 nativePendingDatagramSize() const; + qint64 nativeReceiveDatagram(char *data, qint64 maxLength, + QHostAddress *address, quint16 *port); + qint64 nativeSendDatagram(const char *data, qint64 length, + const QHostAddress &host, quint16 port); + qint64 nativeRead(char *data, qint64 maxLength); + qint64 nativeWrite(const char *data, qint64 length); + int nativeSelect(int timeout, bool selectForRead) const; + int nativeSelect(int timeout, bool checkRead, bool checkWrite, + bool *selectForRead, bool *selectForWrite) const; + + void nativeClose(); + + bool checkProxy(const QHostAddress &address); + bool fetchConnectionParameters(); +}; + +QT_END_NAMESPACE + +#endif // QNATIVESOCKETENGINE_P_H diff --git a/src/network/socket/socket.pri b/src/network/socket/socket.pri index f2262fe..3356cdd 100644 --- a/src/network/socket/socket.pri +++ b/src/network/socket/socket.pri @@ -26,7 +26,10 @@ SOURCES += socket/qabstractsocketengine.cpp \ socket/qlocalserver.cpp unix:!symbian:SOURCES += socket/qnativesocketengine_unix.cpp -symbian:SOURCES += socket/qnativesocketengine_symbian.cpp + +symbian:SOURCES += socket/qsymbiansocketengine.cpp +symbian:HEADERS += socket/qsymbiansocketengine_p.h + unix:SOURCES += \ socket/qlocalsocket_unix.cpp \ socket/qlocalserver_unix.cpp -- cgit v0.12 From 2073995a5af4d6a7677f78757aa72e598ef4b1ac Mon Sep 17 00:00:00 2001 From: Aaron Tunney Date: Tue, 7 Dec 2010 16:10:55 +0000 Subject: Fixed typo and includes. Reviewed-by: Markus Goetz --- src/network/kernel/qhostinfo_symbian.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/network/kernel/qhostinfo_symbian.cpp b/src/network/kernel/qhostinfo_symbian.cpp index 2e1e6ca..ffa0b46 100644 --- a/src/network/kernel/qhostinfo_symbian.cpp +++ b/src/network/kernel/qhostinfo_symbian.cpp @@ -40,6 +40,8 @@ ****************************************************************************/ //#define QHOSTINFO_DEBUG +#include +#include #include "qplatformdefs.h" @@ -92,7 +94,7 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) QString QHostInfo::localHostName() { - return QString() + return QString(); } QString QHostInfo::localDomainName() -- cgit v0.12 From 443d9e8a951ead746bd92ddb3835cd9cd63a063b Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Tue, 7 Dec 2010 16:17:19 +0100 Subject: Continue code moving Reviewed-by: Shane Kearns --- src/network/socket/qsymbiansocketengine.cpp | 120 ++++++++++++++-------------- src/network/socket/qsymbiansocketengine_p.h | 114 +++++--------------------- 2 files changed, 80 insertions(+), 154 deletions(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index cfaee03..b553110 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -95,7 +95,7 @@ static QByteArray qt_prettyDebug(const char *data, int len, int maxSize) } #endif -void QNativeSocketEnginePrivate::getPortAndAddress(const TInetAddr& a, quint16 *port, QHostAddress *addr) +void QSymbianSocketEnginePrivate::getPortAndAddress(const TInetAddr& a, quint16 *port, QHostAddress *addr) { #if !defined(QT_NO_IPV6) if (a.Family() == KAfInet6) { @@ -133,7 +133,7 @@ void QNativeSocketEnginePrivate::getPortAndAddress(const TInetAddr& a, quint16 * Creates and returns a new socket descriptor of type \a socketType and \a socketProtocol. Returns -1 on failure. */ -bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType, +bool QSymbianSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType, QAbstractSocket::NetworkLayerProtocol socketProtocol) { #ifndef QT_NO_IPV6 @@ -176,9 +176,9 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc /* Returns the value of the socket option \a opt. */ -int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) const +int QSymbianSocketEnginePrivate::option(QAbstractSocketEngine::SocketOption opt) const { - Q_Q(const QNativeSocketEngine); + Q_Q(const QSymbianSocketEngine); if (!q->isValid()) return -1; @@ -186,32 +186,32 @@ int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) co TUint level = KSOLSocket; // default switch (opt) { - case QNativeSocketEngine::ReceiveBufferSocketOption: + case QAbstractSocketEngine::ReceiveBufferSocketOption: n = KSORecvBuf; break; - case QNativeSocketEngine::SendBufferSocketOption: + case QAbstractSocketEngine::SendBufferSocketOption: n = KSOSendBuf; break; - case QNativeSocketEngine::NonBlockingSocketOption: + case QAbstractSocketEngine::NonBlockingSocketOption: n = KSONonBlockingIO; break; - case QNativeSocketEngine::BroadcastSocketOption: + case QAbstractSocketEngine::BroadcastSocketOption: return true; //symbian doesn't support or require this option - case QNativeSocketEngine::AddressReusable: + case QAbstractSocketEngine::AddressReusable: level = KSolInetIp; n = KSoReuseAddr; break; - case QNativeSocketEngine::BindExclusively: + case QAbstractSocketEngine::BindExclusively: return true; - case QNativeSocketEngine::ReceiveOutOfBandData: + case QAbstractSocketEngine::ReceiveOutOfBandData: level = KSolInetTcp; n = KSoTcpOobInline; break; - case QNativeSocketEngine::LowDelayOption: + case QAbstractSocketEngine::LowDelayOption: level = KSolInetTcp; n = KSoTcpNoDelay; break; - case QNativeSocketEngine::KeepAliveOption: + case QAbstractSocketEngine::KeepAliveOption: level = KSolInetTcp; n = KSoTcpKeepAlive; break; @@ -232,9 +232,9 @@ int QNativeSocketEnginePrivate::option(QNativeSocketEngine::SocketOption opt) co /* Sets the socket option \a opt to \a v. */ -bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt, int v) +bool QSymbianSocketEngine::setOption(QAbstractSocketEngine::SocketOption opt, int v) { - Q_Q(QNativeSocketEngine); + Q_Q(QSymbianSocketEngine); if (!q->isValid()) return false; @@ -242,32 +242,32 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt int level = SOL_SOCKET; // default switch (opt) { - case QNativeSocketEngine::ReceiveBufferSocketOption: + case QAbstractSocketEngine::ReceiveBufferSocketOption: n = KSORecvBuf; break; - case QNativeSocketEngine::SendBufferSocketOption: + case QAbstractSocketEngine::SendBufferSocketOption: n = KSOSendBuf; break; - case QNativeSocketEngine::BroadcastSocketOption: + case QAbstractSocketEngine::BroadcastSocketOption: return true; - case QNativeSocketEngine::NonBlockingSocketOption: + case QAbstractSocketEngine::NonBlockingSocketOption: n = KSONonBlockingIO; break; - case QNativeSocketEngine::AddressReusable: + case QAbstractSocketEngine::AddressReusable: level = KSolInetIp; n = KSoReuseAddr; break; - case QNativeSocketEngine::BindExclusively: + case QAbstractSocketEngine::BindExclusively: return true; - case QNativeSocketEngine::ReceiveOutOfBandData: + case QAbstractSocketEngine::ReceiveOutOfBandData: level = KSolInetTcp; n = KSoTcpOobInline; break; - case QNativeSocketEngine::LowDelayOption: + case QAbstractSocketEngine::LowDelayOption: level = KSolInetTcp; n = KSoTcpNoDelay; break; - case QNativeSocketEngine::KeepAliveOption: + case QAbstractSocketEngine::KeepAliveOption: level = KSolInetTcp; n = KSoTcpKeepAlive; break; @@ -276,7 +276,7 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt return (KErrNone == nativeSocket.SetOpt(n, level, v)); } -void QNativeSocketEnginePrivate::setPortAndAddress(TInetAddr& nativeAddr, quint16 port, const QHostAddress &addr) +void QSymbianSocketEnginePrivate::setPortAndAddress(TInetAddr& nativeAddr, quint16 port, const QHostAddress &addr) { nativeAddr.SetPort(port); #if !defined(QT_NO_IPV6) @@ -305,10 +305,10 @@ void QNativeSocketEnginePrivate::setPortAndAddress(TInetAddr& nativeAddr, quint1 } } -bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16 port) +bool QSymbianSocketEngine::connect(const QHostAddress &addr, quint16 port) { #ifdef QNATIVESOCKETENGINE_DEBUG - qDebug("QNativeSocketEnginePrivate::nativeConnect() : %d ", socketDescriptor); + qDebug("QSymbianSocketEnginePrivate::nativeConnect() : %d ", socketDescriptor); #endif TInetAddr nativeAddr; @@ -351,7 +351,7 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16 if (socketState != QAbstractSocket::ConnectedState) { #if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeConnect(%s, %i) == false (%s)", + qDebug("QSymbianSocketEnginePrivate::nativeConnect(%s, %i) == false (%s)", addr.toString().toLatin1().constData(), port, socketState == QAbstractSocket::ConnectingState ? "Connection in progress" : socketErrorString.toLatin1().constData()); @@ -369,7 +369,7 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16 return true; } -bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, quint16 port) +bool QSymbianSocketEngine::bind(const QHostAddress &address, quint16 port) { TInetAddr nativeAddr; setPortAndAddress(nativeAddr, port, address); @@ -392,7 +392,7 @@ bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, quint16 } #if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeBind(%s, %i) == false (%s)", + qDebug("QSymbianSocketEnginePrivate::nativeBind(%s, %i) == false (%s)", address.toString().toLatin1().constData(), port, socketErrorString.toLatin1().constData()); #endif @@ -400,14 +400,14 @@ bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, quint16 } #if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeBind(%s, %i) == true", + qDebug("QSymbianSocketEnginePrivate::nativeBind(%s, %i) == true", address.toString().toLatin1().constData(), port); #endif socketState = QAbstractSocket::BoundState; return true; } -bool QNativeSocketEnginePrivate::nativeListen(int backlog) +bool QSymbianSocketEngine::listen(int backlog) { TInt err = nativeSocket.Listen(backlog); if (err) { @@ -421,21 +421,21 @@ bool QNativeSocketEnginePrivate::nativeListen(int backlog) } #if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeListen(%i) == false (%s)", + qDebug("QSymbianSocketEnginePrivate::nativeListen(%i) == false (%s)", backlog, socketErrorString.toLatin1().constData()); #endif return false; } #if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeListen(%i) == true", backlog); + qDebug("QSymbianSocketEnginePrivate::nativeListen(%i) == true", backlog); #endif socketState = QAbstractSocket::ListeningState; return true; } -int QNativeSocketEnginePrivate::nativeAccept() +int QSymbianSocketEngine::accept() { RSocket blankSocket; //TODO: this is unbelievably broken, needs to be properly async @@ -444,7 +444,7 @@ int QNativeSocketEnginePrivate::nativeAccept() nativeSocket.Accept(blankSocket, status); User::WaitForRequest(status); if(status.Int()) { - qWarning("QNativeSocketEnginePrivate::nativeAccept() - error %d", status.Int()); + qWarning("QSymbianSocketEnginePrivate::nativeAccept() - error %d", status.Int()); return 0; } // FIXME Qt Handle of new socket must be retrieved from QSymbianSocketManager @@ -452,7 +452,7 @@ int QNativeSocketEnginePrivate::nativeAccept() return blankSocket.SubSessionHandle(); } -qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const +qint64 QSymbianSocketEngine::bytesAvailable() const { int nbytes = 0; qint64 available = 0; @@ -464,12 +464,12 @@ qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const available = (qint64) nbytes; #if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeBytesAvailable() == %lli", available); + qDebug("QSymbianSocketEnginePrivate::nativeBytesAvailable() == %lli", available); #endif return available; } -bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const +bool QSymbianSocketEngine::hasPendingDatagrams() const { int nbytes; TInt err = nativeSocket.GetOpt(KSOReadBytesPending,KSOLSocket, nbytes); @@ -477,7 +477,7 @@ bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const //TODO: this is pretty horrible too... } -qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const +qint64 QSymbianSocketEngine::pendingDatagramSize() const { int nbytes; TInt err = nativeSocket.GetOpt(KSOReadBytesPending,KSOLSocket, nbytes); @@ -486,7 +486,7 @@ qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const // this could be pretty broken, especially for IPv6 } -qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxSize, +qint64 QSymbianSocketEngine::nativeReceiveDatagram(char *data, qint64 maxSize, QHostAddress *address, quint16 *port) { TPtr8 buffer((TUint8*)data, (int)maxSize); @@ -503,7 +503,7 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxS #if defined (QNATIVESOCKETENGINE_DEBUG) int len = buffer.Length(); - qDebug("QNativeSocketEnginePrivate::nativeReceiveDatagram(%p \"%s\", %lli, %s, %i) == %lli", + qDebug("QSymbianSocketEnginePrivate::nativeReceiveDatagram(%p \"%s\", %lli, %s, %i) == %lli", data, qt_prettyDebug(data, qMin(len, ssize_t(16)), len).data(), maxSize, address ? address->toString().toLatin1().constData() : "(nil)", port ? *port : 0, (qint64) len); @@ -514,7 +514,7 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxS return qint64(buffer.Length()); } -qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 len, +qint64 QSymbianSocketEngine::sendDatagram(const char *data, qint64 len, const QHostAddress &host, quint16 port) { TPtrC8 buffer((TUint8*)data, (int)len); @@ -537,7 +537,7 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l } #if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEngine::sendDatagram(%p \"%s\", %lli, \"%s\", %i) == %lli", data, + qDebug("QSymbianSocketEnginePrivate::sendDatagram(%p \"%s\", %lli, \"%s\", %i) == %lli", data, qt_prettyDebug(data, qMin(len, 16), len).data(), len, host.toString().toLatin1().constData(), port, (qint64) sentBytes()); #endif @@ -545,7 +545,7 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l return qint64(sentBytes()); } -bool QNativeSocketEnginePrivate::fetchConnectionParameters() +bool QSymbianSocketEnginePrivate::fetchConnectionParameters() { localPort = 0; localAddress.clear(); @@ -611,7 +611,7 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters() if (socketType == QAbstractSocket::TcpSocket) socketTypeStr = "TcpSocket"; else if (socketType == QAbstractSocket::UdpSocket) socketTypeStr = "UdpSocket"; - qDebug("QNativeSocketEnginePrivate::fetchConnectionParameters() local == %s:%i," + qDebug("QSymbianSocketEnginePrivate::fetchConnectionParameters() local == %s:%i," " peer == %s:%i, socket == %s - %s", localAddress.toString().toLatin1().constData(), localPort, peerAddress.toString().toLatin1().constData(), peerPort,socketTypeStr.toLatin1().constData(), @@ -620,10 +620,10 @@ bool QNativeSocketEnginePrivate::fetchConnectionParameters() return true; } -void QNativeSocketEnginePrivate::nativeClose() +void QSymbianSocketEngine::close() { #if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEngine::nativeClose()"); + qDebug("QSymbianSocketEnginePrivate::nativeClose()"); #endif //TODO: call nativeSocket.Shutdown(EImmediate) in some cases? @@ -631,9 +631,9 @@ void QNativeSocketEnginePrivate::nativeClose() QSymbianSocketManager::instance().removeSocket(nativeSocket); } -qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len) +qint64 QSymbianSocketEngine::write(const char *data, qint64 len) { - Q_Q(QNativeSocketEngine); + Q_Q(QSymbianSocketEngine); TPtrC8 buffer((TUint8*)data, (int)len); TSockXfrLength sentBytes; TRequestStatus status; //TODO: OMG sync send! @@ -659,7 +659,7 @@ qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len) } #if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeWrite(%p \"%s\", %llu) == %i", + qDebug("QSymbianSocketEnginePrivate::nativeWrite(%p \"%s\", %llu) == %i", data, qt_prettyDebug(data, qMin((int) len, 16), (int) len).data(), len, (int) sentBytes()); #endif @@ -668,11 +668,11 @@ qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len) } /* */ -qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize) +qint64 QSymbianSocketEngine::read(char *data, qint64 maxSize) { - Q_Q(QNativeSocketEngine); + Q_Q(QSymbianSocketEngine); if (!q->isValid()) { - qWarning("QNativeSocketEngine::nativeRead: Invalid socket"); + qWarning("QSymbianSocketEnginePrivate::nativeRead: Invalid socket"); return -1; } @@ -709,7 +709,7 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize) return qint64(r); } -int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const +int QSymbianSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const { bool readyRead = false; bool readyWrite = false; @@ -728,7 +728,7 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) co \param selectForWrite (out) should set to true if ready to write \return 0 on timeout, >0 on success, <0 on error */ -int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool checkWrite, +int QSymbianSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool checkWrite, bool *selectForRead, bool *selectForWrite) const { //TODO: implement @@ -777,27 +777,27 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool c return 1; } -bool QNativeSocketEnginePrivate::nativeJoinMulticastGroup(const QHostAddress &groupAddress, +bool QSymbianSocketEngine::joinMulticastGroup(const QHostAddress &groupAddress, const QNetworkInterface &iface) { //TODO return false; } -bool QNativeSocketEnginePrivate::nativeLeaveMulticastGroup(const QHostAddress &groupAddress, +bool QSymbianSocketEngine::leaveMulticastGroup(const QHostAddress &groupAddress, const QNetworkInterface &iface) { //TODO return false; } -QNetworkInterface QNativeSocketEnginePrivate::nativeMulticastInterface() const +QNetworkInterface QSymbianSocketEngine::multicastInterface() const { //TODO return QNetworkInterface(); } -bool QNativeSocketEnginePrivate::nativeSetMulticastInterface(const QNetworkInterface &iface) +bool QSymbianSocketEngine::setMulticastInterface(const QNetworkInterface &iface) { //TODO return false; diff --git a/src/network/socket/qsymbiansocketengine_p.h b/src/network/socket/qsymbiansocketengine_p.h index c017065..07e1b69 100644 --- a/src/network/socket/qsymbiansocketengine_p.h +++ b/src/network/socket/qsymbiansocketengine_p.h @@ -39,8 +39,8 @@ ** ****************************************************************************/ -#ifndef QNATIVESOCKETENGINE_P_H -#define QNATIVESOCKETENGINE_P_H +#ifndef QSYMBIANSOCKETENGINE_P_H +#define QSYMBIANSOCKETENGINE_P_H // // W A R N I N G @@ -54,63 +54,27 @@ // #include "QtNetwork/qhostaddress.h" #include "private/qabstractsocketengine_p.h" -#ifndef Q_OS_WIN -# include "qplatformdefs.h" -#else -# include -#endif +#include "qplatformdefs.h" -#ifdef Q_OS_SYMBIAN #include #include #include #include -#endif +// TODO -QT_BEGIN_NAMESPACE -// Use our own defines and structs which we know are correct -# define QT_SS_MAXSIZE 128 -# define QT_SS_ALIGNSIZE (sizeof(qint64)) -# define QT_SS_PAD1SIZE (QT_SS_ALIGNSIZE - sizeof (short)) -# define QT_SS_PAD2SIZE (QT_SS_MAXSIZE - (sizeof (short) + QT_SS_PAD1SIZE + QT_SS_ALIGNSIZE)) -struct qt_sockaddr_storage { - short ss_family; - char __ss_pad1[QT_SS_PAD1SIZE]; - qint64 __ss_align; - char __ss_pad2[QT_SS_PAD2SIZE]; -}; +QT_BEGIN_NAMESPACE -// sockaddr_in6 size changed between old and new SDK -// Only the new version is the correct one, so always -// use this structure. -struct qt_in6_addr { - quint8 qt_s6_addr[16]; -}; -struct qt_sockaddr_in6 { - short sin6_family; /* AF_INET6 */ - quint16 sin6_port; /* Transport level port number */ - quint32 sin6_flowinfo; /* IPv6 flow information */ - struct qt_in6_addr sin6_addr; /* IPv6 address */ - quint32 sin6_scope_id; /* set of interfaces for a scope */ -}; -union qt_sockaddr { - sockaddr a; - sockaddr_in a4; - qt_sockaddr_in6 a6; - qt_sockaddr_storage storage; -}; - -class QNativeSocketEnginePrivate; +class QSymbianSocketEnginePrivate; class QNetworkInterface; -class Q_AUTOTEST_EXPORT QNativeSocketEngine : public QAbstractSocketEngine +class Q_AUTOTEST_EXPORT QSymbianSocketEngine : public QAbstractSocketEngine { Q_OBJECT public: - QNativeSocketEngine(QObject *parent = 0); - ~QNativeSocketEngine(); + QSymbianSocketEngine(QObject *parent = 0); + ~QSymbianSocketEngine(); bool initialize(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol = QAbstractSocket::IPv4Protocol); bool initialize(int socketDescriptor, QAbstractSocket::SocketState socketState = QAbstractSocket::ConnectedState); @@ -156,6 +120,7 @@ public: int option(SocketOption option) const; bool setOption(SocketOption option, int value); + // FIXME actually implement bool waitForRead(int msecs = 30000, bool *timedOut = 0); bool waitForWrite(int msecs = 30000, bool *timedOut = 0); bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite, @@ -170,32 +135,23 @@ public: void setExceptionNotificationEnabled(bool enable); public Q_SLOTS: + // TODO: Why do we do this? This is private Qt implementation stuff anyway, no need for it // non-virtual override; void connectionNotification(); private: - Q_DECLARE_PRIVATE(QNativeSocketEngine) - Q_DISABLE_COPY(QNativeSocketEngine) -}; - -#ifdef Q_OS_WIN -class QWindowsSockInit -{ -public: - QWindowsSockInit(); - ~QWindowsSockInit(); - int version; + Q_DECLARE_PRIVATE(QSymbianSocketEngine) + Q_DISABLE_COPY(QSymbianSocketEngine) }; -#endif class QSocketNotifier; -class QNativeSocketEnginePrivate : public QAbstractSocketEnginePrivate +class QSymbianSocketEnginePrivate : public QAbstractSocketEnginePrivate { - Q_DECLARE_PUBLIC(QNativeSocketEngine) + Q_DECLARE_PUBLIC(QSymbianSocketEngine) public: - QNativeSocketEnginePrivate(); - ~QNativeSocketEnginePrivate(); + QSymbianSocketEnginePrivate(); + ~QSymbianSocketEnginePrivate(); int socketDescriptor; #ifdef Q_OS_SYMBIAN @@ -207,10 +163,6 @@ public: QSocketNotifier *readNotifier, *writeNotifier, *exceptNotifier; -#ifdef Q_OS_WIN - QWindowsSockInit winSock; -#endif - enum ErrorString { NonBlockingInitFailedErrorString, BroadcastingInitFailedErrorString, @@ -248,37 +200,11 @@ public: #endif void setError(QAbstractSocket::SocketError error, ErrorString errorString) const; - // native functions - int option(QNativeSocketEngine::SocketOption option) const; - bool setOption(QNativeSocketEngine::SocketOption option, int value); - - bool createNewSocket(QAbstractSocket::SocketType type, QAbstractSocket::NetworkLayerProtocol protocol); - - bool nativeConnect(const QHostAddress &address, quint16 port); - bool nativeBind(const QHostAddress &address, quint16 port); - bool nativeListen(int backlog); - int nativeAccept(); - bool nativeJoinMulticastGroup(const QHostAddress &groupAddress, - const QNetworkInterface &iface); - bool nativeLeaveMulticastGroup(const QHostAddress &groupAddress, - const QNetworkInterface &iface); - QNetworkInterface nativeMulticastInterface() const; - bool nativeSetMulticastInterface(const QNetworkInterface &iface); - qint64 nativeBytesAvailable() const; - - bool nativeHasPendingDatagrams() const; - qint64 nativePendingDatagramSize() const; - qint64 nativeReceiveDatagram(char *data, qint64 maxLength, - QHostAddress *address, quint16 *port); - qint64 nativeSendDatagram(const char *data, qint64 length, - const QHostAddress &host, quint16 port); - qint64 nativeRead(char *data, qint64 maxLength); - qint64 nativeWrite(const char *data, qint64 length); + // FIXME int nativeSelect(int timeout, bool selectForRead) const; int nativeSelect(int timeout, bool checkRead, bool checkWrite, - bool *selectForRead, bool *selectForWrite) const; + bool *selectForRead, bool *selectForWrite) const; - void nativeClose(); bool checkProxy(const QHostAddress &address); bool fetchConnectionParameters(); @@ -286,4 +212,4 @@ public: QT_END_NAMESPACE -#endif // QNATIVESOCKETENGINE_P_H +#endif // QSYMBIANSOCKETENGINE_P_H -- cgit v0.12 From 8adba785c8b68b9fdc98b51ecf317e17ad145d13 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 7 Dec 2010 16:03:09 +0000 Subject: default RConnection for sockets Bearer pushes RConnection into QtCore. QSocket can pull this RConnection back out when it needs to open an RSocket (potentially this can be removed again later if QSocket is made QNetworkSession aware) Reviewed-by: Markus Goetz --- src/corelib/kernel/qcore_symbian_p.cpp | 12 +++++++++++- src/corelib/kernel/qcore_symbian_p.h | 16 +++++++++++++++- src/plugins/bearer/symbian/qnetworksession_impl.cpp | 10 ++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/corelib/kernel/qcore_symbian_p.cpp b/src/corelib/kernel/qcore_symbian_p.cpp index b6688f7..ede8464 100644 --- a/src/corelib/kernel/qcore_symbian_p.cpp +++ b/src/corelib/kernel/qcore_symbian_p.cpp @@ -217,7 +217,7 @@ Q_CORE_EXPORT RFs& qt_s60GetRFs() } QSymbianSocketManager::QSymbianSocketManager() : - iNextSocket(0) + iNextSocket(0), iDefaultConnection(0) { TSessionPref preferences; // ### In future this could be changed to KAfInet6 when that is more common than IPv4 @@ -290,6 +290,16 @@ bool QSymbianSocketManager::lookupSocket(int fd, RSocket& socket) const { return true; } +void QSymbianSocketManager::setDefaultConnection(RConnection* con) +{ + iDefaultConnection = con; +} + +RConnection* QSymbianSocketManager::defaultConnection() const +{ + return iDefaultConnection; +} + Q_GLOBAL_STATIC(QSymbianSocketManager, qt_symbianSocketManager); QSymbianSocketManager& QSymbianSocketManager::instance() diff --git a/src/corelib/kernel/qcore_symbian_p.h b/src/corelib/kernel/qcore_symbian_p.h index 8ffa247..d5d10ef 100644 --- a/src/corelib/kernel/qcore_symbian_p.h +++ b/src/corelib/kernel/qcore_symbian_p.h @@ -172,7 +172,7 @@ public: } bool operator<(const QHashableSocket &other) const { - if(Session().Handle() == other.Session().Handle()) + if (Session().Handle() == other.Session().Handle()) return SubSessionHandle() < other.SubSessionHandle(); return Session().Handle() < other.Session().Handle(); } @@ -230,6 +230,19 @@ public: /*! \internal + Set the default connection to use for new sockets + \param an open connection + */ + void setDefaultConnection(RConnection* con); + /*! + \internal + Get the default connection to use for new sockets + \return the connection, or null pointer if there is none set + */ + RConnection *defaultConnection() const; + + /*! + \internal Gets a reference to the singleton socket manager */ static QSymbianSocketManager& instance(); @@ -243,6 +256,7 @@ private: QHash reverseSocketMap; mutable QMutex iMutex; RSocketServ iSocketServ; + RConnection *iDefaultConnection; }; QT_END_NAMESPACE diff --git a/src/plugins/bearer/symbian/qnetworksession_impl.cpp b/src/plugins/bearer/symbian/qnetworksession_impl.cpp index cfb55bf..759c86a 100644 --- a/src/plugins/bearer/symbian/qnetworksession_impl.cpp +++ b/src/plugins/bearer/symbian/qnetworksession_impl.cpp @@ -114,6 +114,7 @@ QNetworkSessionPrivateImpl::~QNetworkSessionPrivateImpl() // Close global 'Open C' RConnection // Clears also possible unsetdefaultif() flags. setdefaultif(0); + QSymbianSocketManager::instance().setDefaultConnection(0); iConnectionMonitor.Close(); iOpenCLibrary.Close(); @@ -533,6 +534,7 @@ void QNetworkSessionPrivateImpl::close(bool allowSignals) setdefaultif(0); } + QSymbianSocketManager::instance().setDefaultConnection(0); // If UserChoice, go down immediately. If some other configuration, // go down immediately if there is no reports expected from the platform; // in practice Connection Monitor is aware of connections only after @@ -634,6 +636,7 @@ void QNetworkSessionPrivateImpl::migrate() } else { setdefaultif(0); } + QSymbianSocketManager::instance().setDefaultConnection(0); // Start migrating to new IAP iMobility->MigrateToPreferredCarrier(); } @@ -670,6 +673,8 @@ void QNetworkSessionPrivateImpl::accept() strcpy(ifr.ifr_name, nameAsByteArray.constData()); setdefaultif(&ifr); + QSymbianSocketManager::instance().setDefaultConnection(&iConnection); + newState(QNetworkSession::Connected, iNewRoamingIap); } #endif @@ -693,6 +698,8 @@ void QNetworkSessionPrivateImpl::reject() strcpy(ifr.ifr_name, nameAsByteArray.constData()); setdefaultif(&ifr); + QSymbianSocketManager::instance().setDefaultConnection(&iConnection); + newState(QNetworkSession::Connected, iOldRoamingIap); } } @@ -1079,6 +1086,7 @@ void QNetworkSessionPrivateImpl::RunL() QByteArray nameAsByteArray = newActiveConfig.name().toUtf8(); strcpy(ifr.ifr_name, nameAsByteArray.constData()); error = setdefaultif(&ifr); + QSymbianSocketManager::instance().setDefaultConnection(&iConnection); } if (error != KErrNone) { isOpen = false; @@ -1092,6 +1100,7 @@ void QNetworkSessionPrivateImpl::RunL() // No valid configuration, bail out. // Status updates from QNCM won't be received correctly // because there is no configuration to associate them with so transit here. + QSymbianSocketManager::instance().setDefaultConnection(0); iConnection.Close(); newState(QNetworkSession::Closing); newState(QNetworkSession::Disconnected); @@ -1205,6 +1214,7 @@ bool QNetworkSessionPrivateImpl::newState(QNetworkSession::State newState, TUint strcpy(ifr.ifr_name, nameAsByteArray.constData()); setdefaultif(&ifr); + QSymbianSocketManager::instance().setDefaultConnection(&iConnection); #endif } -- cgit v0.12 From c59b7067ace1abc5f9a0aca9bd90d49340cb4e79 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 7 Dec 2010 16:07:30 +0000 Subject: Helper functions for synchronously waiting on an active object to complete QtNetwork APIs are based on calling a function asychronously. However the user may call a waitForXXXX function later to convert this into a synchronous call. For Symbian, the async call should be implemented as an active object. These helpers make the synchronous conversion possible. Unix used select() in a polling way to do async mode and blocking way for the synchronous conversion. Reviewed-by: mread --- src/corelib/kernel/qeventdispatcher_symbian.cpp | 80 +++++++++++++++++++++++++ src/corelib/kernel/qeventdispatcher_symbian_p.h | 4 +- 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/src/corelib/kernel/qeventdispatcher_symbian.cpp b/src/corelib/kernel/qeventdispatcher_symbian.cpp index 6154119..55be6eb 100644 --- a/src/corelib/kernel/qeventdispatcher_symbian.cpp +++ b/src/corelib/kernel/qeventdispatcher_symbian.cpp @@ -1136,6 +1136,86 @@ void CQtActiveScheduler::Error(TInt aError) const QT_CATCH (const std::bad_alloc&) {} // ignore alloc fails, nothing more can be done } +bool QActiveObject::wait(CActive* ao, int ms) +{ + if (!ao->IsActive()) + return true; //request already complete + bool timedout = false; + if (ms > 0) { + TRequestStatus tstat; + RTimer t; + if (KErrNone != t.CreateLocal()) + return false; + t.HighRes(tstat, ms*1000); + User::WaitForRequest(tstat, ao->iStatus); + if (tstat != KRequestPending) { + timedout = true; + } else { + t.Cancel(); + //balance thread semaphore + User::WaitForRequest(tstat); + } + t.Close(); + } else { + User::WaitForRequest(ao->iStatus); + } + if (timedout) + return false; + + //evil cast to allow calling of protected virtual + ((QActiveObject*)ao)->RunL(); + + //clear active & pending flags + ao->iStatus = TRequestStatus(); + + return true; +} + +bool QActiveObject::wait(QList aos, int ms) +{ + QVector stati; + stati.reserve(aos.count() + 1); + foreach (CActive* ao, aos) { + if (!ao->IsActive()) + return true; //request already complete + stati.append(&(ao->iStatus)); + } + bool timedout = false; + TRequestStatus tstat; + RTimer t; + if (ms > 0) { + if (KErrNone != t.CreateLocal()) + return false; + t.HighRes(tstat, ms*1000); + stati.append(&tstat); + } + User::WaitForNRequest(stati.data(), stati.count()); + if (ms > 0) { + if (tstat != KRequestPending) { + timedout = true; + } else { + t.Cancel(); + //balance thread semaphore + User::WaitForRequest(tstat); + } + t.Close(); + } + if (timedout) + return false; + + foreach (CActive* ao, aos) { + if (ao->iStatus != KRequestPending) { + //evil cast to allow calling of protected virtual + ((QActiveObject*)ao)->RunL(); + + //clear active & pending flags + ao->iStatus = TRequestStatus(); + break; //only call one + } + } + return true; +} + QT_END_NAMESPACE #include "moc_qeventdispatcher_symbian_p.cpp" diff --git a/src/corelib/kernel/qeventdispatcher_symbian_p.h b/src/corelib/kernel/qeventdispatcher_symbian_p.h index 3615996..d462dff 100644 --- a/src/corelib/kernel/qeventdispatcher_symbian_p.h +++ b/src/corelib/kernel/qeventdispatcher_symbian_p.h @@ -76,7 +76,7 @@ QT_BEGIN_NAMESPACE class QEventDispatcherSymbian; class QTimerActiveObject; -class QActiveObject : public CActive +class Q_AUTOTEST_EXPORT QActiveObject : public CActive { public: QActiveObject(TInt priority, QEventDispatcherSymbian *dispatcher); @@ -86,6 +86,8 @@ public: void reactivateAndComplete(); + static bool wait(CActive* ao, int ms); + static bool wait(QList aos, int ms); protected: QEventDispatcherSymbian *m_dispatcher; -- cgit v0.12 From a0528585d02440b37fb93f37e3d15ce2356d2541 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Tue, 7 Dec 2010 16:51:48 +0100 Subject: Remove Symbian code from QNativeSocketEngine .. and move one function around Reviewed-by: Shane Kearns --- src/network/socket/qnativesocketengine.cpp | 8 --- src/network/socket/qnativesocketengine_p.h | 11 ---- src/network/socket/qsymbiansocketengine.cpp | 80 ++++++++++++++++++----------- 3 files changed, 51 insertions(+), 48 deletions(-) diff --git a/src/network/socket/qnativesocketengine.cpp b/src/network/socket/qnativesocketengine.cpp index 00d36b4..1fe5572 100644 --- a/src/network/socket/qnativesocketengine.cpp +++ b/src/network/socket/qnativesocketengine.cpp @@ -110,10 +110,6 @@ # include "qtcpserver.h" #endif -#ifdef Q_OS_SYMBIAN -# include -#endif - QT_BEGIN_NAMESPACE //#define QNATIVESOCKETENGINE_DEBUG @@ -164,9 +160,6 @@ QT_BEGIN_NAMESPACE */ QNativeSocketEnginePrivate::QNativeSocketEnginePrivate() : socketDescriptor(-1), -#ifdef Q_OS_SYMBIAN - socketServer(qt_symbianGetSocketServer()), -#endif readNotifier(0), writeNotifier(0), exceptNotifier(0) @@ -394,7 +387,6 @@ bool QNativeSocketEngine::initialize(QAbstractSocket::SocketType socketType, QAb // Make sure we receive out-of-band data - // On Symbian OS this works only with native IP stack, not with WinSock if (socketType == QAbstractSocket::TcpSocket && !setOption(ReceiveOutOfBandData, 1)) { qWarning("QNativeSocketEngine::initialize unable to inline out-of-band data"); diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h index c017065..1f13433 100644 --- a/src/network/socket/qnativesocketengine_p.h +++ b/src/network/socket/qnativesocketengine_p.h @@ -198,12 +198,6 @@ public: ~QNativeSocketEnginePrivate(); int socketDescriptor; -#ifdef Q_OS_SYMBIAN - mutable RSocket nativeSocket; - RSocketServ& socketServer; - RConnection connection; //TODO: shared ref - mutable RTimer selectTimer; -#endif QSocketNotifier *readNotifier, *writeNotifier, *exceptNotifier; @@ -241,11 +235,6 @@ public: UnknownSocketErrorString = -1 }; -#ifdef Q_OS_SYMBIAN - void getPortAndAddress(const TInetAddr& a, quint16 *port, QHostAddress *addr); - void setPortAndAddress(TInetAddr& nativeAddr, quint16 port, const QHostAddress &addr); - void setError(TInt symbianError); -#endif void setError(QAbstractSocket::SocketError error, ErrorString errorString) const; // native functions diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index b553110..7a22918 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -53,6 +53,7 @@ #ifndef QT_NO_IPV6IFNAME #include #endif +# include #define QNATIVESOCKETENGINE_DEBUG @@ -229,6 +230,56 @@ int QSymbianSocketEnginePrivate::option(QAbstractSocketEngine::SocketOption opt) } +void QSymbianSocketEnginePrivate::setPortAndAddress(TInetAddr& nativeAddr, quint16 port, const QHostAddress &addr) +{ + nativeAddr.SetPort(port); +#if !defined(QT_NO_IPV6) + if (addr.protocol() == QAbstractSocket::IPv6Protocol) { +#ifndef QT_NO_IPV6IFNAME + TPckgBuf query; + query().iName = qt_QString2TPtrC(addr.scopeId()); + TInt err = nativeSocket.GetOpt(KSoInetIfQueryByName, KSolInetIfQuery, query); + if(!err) + nativeAddr.SetScope(query().iIndex); + else + nativeAddr.SetScope(0); +#else + nativeAddr.SetScope(addr.scopeId().toInt()); +#endif + Q_IPV6ADDR ip6 = addr.toIPv6Address(); + TIp6Addr v6addr; + memcpy(v6addr.u.iAddr8, ip6.c, 16); + nativeAddr.SetAddress(v6addr); + } else +#endif + if (addr.protocol() == QAbstractSocket::IPv4Protocol) { + nativeAddr.SetAddress(addr.toIPv4Address()); + } else { + qWarning("unsupported network protocol (%d)", addr.protocol()); + } +} + +QSymbianSocketEnginePrivate::QSymbianSocketEnginePrivate() : + socketDescriptor(-1), + socketServer(qt_symbianGetSocketServer()), + readNotifier(0), + writeNotifier(0), + exceptNotifier(0) +{ +} + + +QSymbianSocketEngine::QSymbianSocketEngine(QObject *parent) + : QAbstractSocketEngine(*new QSymbianSocketEnginePrivate(), parent) +{ +} + + +QSymbianSocketEngine::~QSymbianSocketEngine() +{ + close(); +} + /* Sets the socket option \a opt to \a v. */ @@ -276,35 +327,6 @@ bool QSymbianSocketEngine::setOption(QAbstractSocketEngine::SocketOption opt, in return (KErrNone == nativeSocket.SetOpt(n, level, v)); } -void QSymbianSocketEnginePrivate::setPortAndAddress(TInetAddr& nativeAddr, quint16 port, const QHostAddress &addr) -{ - nativeAddr.SetPort(port); -#if !defined(QT_NO_IPV6) - if (addr.protocol() == QAbstractSocket::IPv6Protocol) { -#ifndef QT_NO_IPV6IFNAME - TPckgBuf query; - query().iName = qt_QString2TPtrC(addr.scopeId()); - TInt err = nativeSocket.GetOpt(KSoInetIfQueryByName, KSolInetIfQuery, query); - if(!err) - nativeAddr.SetScope(query().iIndex); - else - nativeAddr.SetScope(0); -#else - nativeAddr.SetScope(addr.scopeId().toInt()); -#endif - Q_IPV6ADDR ip6 = addr.toIPv6Address(); - TIp6Addr v6addr; - memcpy(v6addr.u.iAddr8, ip6.c, 16); - nativeAddr.SetAddress(v6addr); - } else -#endif - if (addr.protocol() == QAbstractSocket::IPv4Protocol) { - nativeAddr.SetAddress(addr.toIPv4Address()); - } else { - qWarning("unsupported network protocol (%d)", addr.protocol()); - } -} - bool QSymbianSocketEngine::connect(const QHostAddress &addr, quint16 port) { #ifdef QNATIVESOCKETENGINE_DEBUG -- cgit v0.12 From f16b745ca427e75bc045076f5e14742a2a2c713a Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Tue, 7 Dec 2010 17:07:19 +0100 Subject: Create QSymbianSocketEngine when requested Reviewed-by: Shane Kearns --- src/network/socket/qabstractsocketengine.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/network/socket/qabstractsocketengine.cpp b/src/network/socket/qabstractsocketengine.cpp index 79eed8c..1b2a1f4 100644 --- a/src/network/socket/qabstractsocketengine.cpp +++ b/src/network/socket/qabstractsocketengine.cpp @@ -113,7 +113,11 @@ QAbstractSocketEngine *QAbstractSocketEngine::createSocketEngine(QAbstractSocket return 0; #endif +#ifdef Q_OS_SYMBIAN + return new QSymbianSocketEngine(parent); +#else return new QNativeSocketEngine(parent); +#endif } QAbstractSocketEngine *QAbstractSocketEngine::createSocketEngine(int socketDescripter, QObject *parent) @@ -123,7 +127,11 @@ QAbstractSocketEngine *QAbstractSocketEngine::createSocketEngine(int socketDescr if (QAbstractSocketEngine *ret = socketHandlers()->at(i)->createSocketEngine(socketDescripter, parent)) return ret; } +#ifdef Q_OS_SYMBIAN + return new QSymbianSocketEngine(parent); +#else return new QNativeSocketEngine(parent); +#endif } QAbstractSocket::SocketError QAbstractSocketEngine::error() const -- cgit v0.12 From c2f9ec2ae225fbaeaa0e463308427fb075d9c2af Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Tue, 7 Dec 2010 17:23:15 +0100 Subject: QSymbianSocketEngine: Get global RConnection* Reviewed-by: Shane Kearns --- src/network/socket/qsymbiansocketengine.cpp | 3 ++- src/network/socket/qsymbiansocketengine_p.h | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index 7a22918..55fe12b 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -145,7 +145,7 @@ bool QSymbianSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType so #endif TUint type = (socketType == QAbstractSocket::UdpSocket) ? KSockDatagram : KSockStream; TUint protocol = (socketType == QAbstractSocket::UdpSocket) ? KProtocolInetUdp : KProtocolInetTcp; - TInt err = nativeSocket.Open(socketServer, family, type, protocol, connection); + TInt err = nativeSocket.Open(socketServer, family, type, protocol, *connection); if (err != KErrNone) { switch (err) { @@ -262,6 +262,7 @@ void QSymbianSocketEnginePrivate::setPortAndAddress(TInetAddr& nativeAddr, quint QSymbianSocketEnginePrivate::QSymbianSocketEnginePrivate() : socketDescriptor(-1), socketServer(qt_symbianGetSocketServer()), + connection(QSymbianSocketManager::instance().defaultConnection()), readNotifier(0), writeNotifier(0), exceptNotifier(0) diff --git a/src/network/socket/qsymbiansocketengine_p.h b/src/network/socket/qsymbiansocketengine_p.h index 07e1b69..fd449ca 100644 --- a/src/network/socket/qsymbiansocketengine_p.h +++ b/src/network/socket/qsymbiansocketengine_p.h @@ -156,8 +156,10 @@ public: int socketDescriptor; #ifdef Q_OS_SYMBIAN mutable RSocket nativeSocket; + // From QtCore: RSocketServ& socketServer; - RConnection connection; //TODO: shared ref + // From QtCore, check lifetime issues, also should be pulling this out of a QNetworkSession somehow: + RConnection *connection; mutable RTimer selectTimer; #endif -- cgit v0.12 From e879d46b2733aa3fe69a3e1dabd2ae377b8a714d Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Wed, 8 Dec 2010 09:51:04 +0100 Subject: QSymbianSocketEngine: Compile fixes.. --- src/network/socket/qabstractsocketengine.cpp | 6 + src/network/socket/qsymbiansocketengine.cpp | 235 ++++++++++++++++++--------- src/network/socket/qsymbiansocketengine_p.h | 2 + 3 files changed, 169 insertions(+), 74 deletions(-) diff --git a/src/network/socket/qabstractsocketengine.cpp b/src/network/socket/qabstractsocketengine.cpp index 1b2a1f4..16b9d57 100644 --- a/src/network/socket/qabstractsocketengine.cpp +++ b/src/network/socket/qabstractsocketengine.cpp @@ -40,7 +40,13 @@ ****************************************************************************/ #include "qabstractsocketengine_p.h" + +#ifdef Q_OS_SYMBIAN +#include "qsymbiansocketengine_p.h" +#else #include "qnativesocketengine_p.h" +#endif + #include "qmutex.h" #include "qnetworkproxy.h" diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index 55fe12b..7957baf 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -40,8 +40,8 @@ ****************************************************************************/ //#define QNATIVESOCKETENGINE_DEBUG -#include "qnativesocketengine_p.h" -#include "private/qnet_unix_p.h" +#include "qsymbiansocketengine_p.h" + #include "qiodevice.h" #include "qhostaddress.h" #include "qelapsedtimer.h" @@ -49,11 +49,17 @@ #include "qnetworkinterface.h" #include #include -#include #ifndef QT_NO_IPV6IFNAME #include #endif -# include + +#include + +#if !defined(QT_NO_NETWORKPROXY) +# include "qnetworkproxy.h" +# include "qabstractsocket.h" +# include "qtcpserver.h" +#endif #define QNATIVESOCKETENGINE_DEBUG @@ -137,6 +143,7 @@ void QSymbianSocketEnginePrivate::getPortAndAddress(const TInetAddr& a, quint16 bool QSymbianSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType socketType, QAbstractSocket::NetworkLayerProtocol socketProtocol) { + Q_Q(QSymbianSocketEngine); #ifndef QT_NO_IPV6 TUint family = (socketProtocol == QAbstractSocket::IPv6Protocol) ? KAfInet6 : KAfInet; #else @@ -177,10 +184,10 @@ bool QSymbianSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType so /* Returns the value of the socket option \a opt. */ -int QSymbianSocketEnginePrivate::option(QAbstractSocketEngine::SocketOption opt) const +int QSymbianSocketEngine::option(QAbstractSocketEngine::SocketOption opt) const { - Q_Q(const QSymbianSocketEngine); - if (!q->isValid()) + Q_D(const QSymbianSocketEngine); + if (!isValid()) return -1; TUint n; @@ -222,7 +229,7 @@ int QSymbianSocketEnginePrivate::option(QAbstractSocketEngine::SocketOption opt) int v = -1; //GetOpt() is non const - TInt err = nativeSocket.GetOpt(n, level, v); + TInt err = d->nativeSocket.GetOpt(n, level, v); if (!err) return v; @@ -269,6 +276,10 @@ QSymbianSocketEnginePrivate::QSymbianSocketEnginePrivate() : { } +QSymbianSocketEnginePrivate::~QSymbianSocketEnginePrivate() +{ +} + QSymbianSocketEngine::QSymbianSocketEngine(QObject *parent) : QAbstractSocketEngine(*new QSymbianSocketEnginePrivate(), parent) @@ -279,6 +290,7 @@ QSymbianSocketEngine::QSymbianSocketEngine(QObject *parent) QSymbianSocketEngine::~QSymbianSocketEngine() { close(); + // FIXME what else do we need to free? } /* @@ -286,8 +298,8 @@ QSymbianSocketEngine::~QSymbianSocketEngine() */ bool QSymbianSocketEngine::setOption(QAbstractSocketEngine::SocketOption opt, int v) { - Q_Q(QSymbianSocketEngine); - if (!q->isValid()) + Q_D(QSymbianSocketEngine); + if (!isValid()) return false; int n = 0; @@ -325,59 +337,82 @@ bool QSymbianSocketEngine::setOption(QAbstractSocketEngine::SocketOption opt, in break; } - return (KErrNone == nativeSocket.SetOpt(n, level, v)); + return (KErrNone == d->nativeSocket.SetOpt(n, level, v)); } -bool QSymbianSocketEngine::connect(const QHostAddress &addr, quint16 port) +bool QSymbianSocketEngine::connectToHostByName(const QString &name, quint16 port) { + // FIXME for engines that support hostnames.. not for us then i guess. + + return false; +} + + +bool QSymbianSocketEngine::connectToHost(const QHostAddress &addr, quint16 port) +{ + Q_D(QSymbianSocketEngine); + #ifdef QNATIVESOCKETENGINE_DEBUG - qDebug("QSymbianSocketEnginePrivate::nativeConnect() : %d ", socketDescriptor); + qDebug("QSymbianSocketEngine::connectToHost() : %d ", d->socketDescriptor); #endif +#if defined (QT_NO_IPV6) + if (addr.protocol() == QAbstractSocket::IPv6Protocol) { + d->setError(QAbstractSocket::UnsupportedSocketOperationError, + NoIpV6ErrorString); + return false; + } +#endif + if (!d->checkProxy(addr)) + return false; + + d->peerAddress = addr; + d->peerPort = port; + TInetAddr nativeAddr; - setPortAndAddress(nativeAddr, port, addr); + d->setPortAndAddress(nativeAddr, port, addr); //TODO: async connect with active object - from here to end of function is a mess TRequestStatus status; - nativeSocket.Connect(nativeAddr, status); + d->nativeSocket.Connect(nativeAddr, status); User::WaitForRequest(status); TInt err = status.Int(); if (err) { switch (err) { case KErrCouldNotConnect: - setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString); - socketState = QAbstractSocket::UnconnectedState; + d->setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString); + d->socketState = QAbstractSocket::UnconnectedState; break; case KErrTimedOut: - setError(QAbstractSocket::NetworkError, ConnectionTimeOutErrorString); + d->setError(QAbstractSocket::NetworkError, ConnectionTimeOutErrorString); break; case KErrHostUnreach: - setError(QAbstractSocket::NetworkError, HostUnreachableErrorString); - socketState = QAbstractSocket::UnconnectedState; + d->setError(QAbstractSocket::NetworkError, HostUnreachableErrorString); + d->socketState = QAbstractSocket::UnconnectedState; break; case KErrNetUnreach: - setError(QAbstractSocket::NetworkError, NetworkUnreachableErrorString); - socketState = QAbstractSocket::UnconnectedState; + d->setError(QAbstractSocket::NetworkError, NetworkUnreachableErrorString); + d->socketState = QAbstractSocket::UnconnectedState; break; case KErrInUse: - setError(QAbstractSocket::NetworkError, AddressInuseErrorString); + d->setError(QAbstractSocket::NetworkError, AddressInuseErrorString); break; case KErrPermissionDenied: - setError(QAbstractSocket::SocketAccessError, AccessErrorString); - socketState = QAbstractSocket::UnconnectedState; + d->setError(QAbstractSocket::SocketAccessError, AccessErrorString); + d->socketState = QAbstractSocket::UnconnectedState; break; case KErrNotSupported: case KErrBadDescriptor: - socketState = QAbstractSocket::UnconnectedState; + d->socketState = QAbstractSocket::UnconnectedState; default: break; } - if (socketState != QAbstractSocket::ConnectedState) { + if (d->socketState != QAbstractSocket::ConnectedState) { #if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QSymbianSocketEnginePrivate::nativeConnect(%s, %i) == false (%s)", addr.toString().toLatin1().constData(), port, - socketState == QAbstractSocket::ConnectingState - ? "Connection in progress" : socketErrorString.toLatin1().constData()); + d->socketState == QAbstractSocket::ConnectingState + ? "Connection in progress" : d->socketErrorString.toLatin1().constData()); #endif return false; } @@ -388,27 +423,29 @@ bool QSymbianSocketEngine::connect(const QHostAddress &addr, quint16 port) addr.toString().toLatin1().constData(), port); #endif - socketState = QAbstractSocket::ConnectedState; + d->socketState = QAbstractSocket::ConnectedState; + d->fetchConnectionParameters(); return true; } bool QSymbianSocketEngine::bind(const QHostAddress &address, quint16 port) { + Q_D(QSymbianSocketEngine); TInetAddr nativeAddr; - setPortAndAddress(nativeAddr, port, address); + d->setPortAndAddress(nativeAddr, port, address); - TInt err = nativeSocket.Bind(nativeAddr); + TInt err = d->nativeSocket.Bind(nativeAddr); if (err) { switch(errno) { case KErrInUse: - setError(QAbstractSocket::AddressInUseError, AddressInuseErrorString); + d->setError(QAbstractSocket::AddressInUseError, AddressInuseErrorString); break; case KErrPermissionDenied: - setError(QAbstractSocket::SocketAccessError, AddressProtectedErrorString); + d->setError(QAbstractSocket::SocketAccessError, AddressProtectedErrorString); break; case KErrNotSupported: - setError(QAbstractSocket::UnsupportedSocketOperationError, OperationUnsupportedErrorString); + d->setError(QAbstractSocket::UnsupportedSocketOperationError, OperationUnsupportedErrorString); break; default: break; @@ -416,7 +453,7 @@ bool QSymbianSocketEngine::bind(const QHostAddress &address, quint16 port) #if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QSymbianSocketEnginePrivate::nativeBind(%s, %i) == false (%s)", - address.toString().toLatin1().constData(), port, socketErrorString.toLatin1().constData()); + address.toString().toLatin1().constData(), port, d->socketErrorString.toLatin1().constData()); #endif return false; @@ -426,17 +463,20 @@ bool QSymbianSocketEngine::bind(const QHostAddress &address, quint16 port) qDebug("QSymbianSocketEnginePrivate::nativeBind(%s, %i) == true", address.toString().toLatin1().constData(), port); #endif - socketState = QAbstractSocket::BoundState; + d->socketState = QAbstractSocket::BoundState; return true; } -bool QSymbianSocketEngine::listen(int backlog) +bool QSymbianSocketEngine::listen() { - TInt err = nativeSocket.Listen(backlog); + Q_D(QSymbianSocketEngine); + // TODO the value 50 is from the QNativeSocketEngine. Maybe it's a bit too much + // for a mobile platform + TInt err = d->nativeSocket.Listen(50); if (err) { switch (errno) { case KErrInUse: - setError(QAbstractSocket::AddressInUseError, + d->setError(QAbstractSocket::AddressInUseError, PortInuseErrorString); break; default: @@ -444,27 +484,28 @@ bool QSymbianSocketEngine::listen(int backlog) } #if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QSymbianSocketEnginePrivate::nativeListen(%i) == false (%s)", - backlog, socketErrorString.toLatin1().constData()); + qDebug("QSymbianSocketEnginePrivate::nativeListen() == false (%s)", + d->socketErrorString.toLatin1().constData()); #endif return false; } #if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QSymbianSocketEnginePrivate::nativeListen(%i) == true", backlog); + qDebug("QSymbianSocketEnginePrivate::nativeListen() == true"); #endif - socketState = QAbstractSocket::ListeningState; + d->socketState = QAbstractSocket::ListeningState; return true; } int QSymbianSocketEngine::accept() { + Q_D(QSymbianSocketEngine); RSocket blankSocket; //TODO: this is unbelievably broken, needs to be properly async - blankSocket.Open(socketServer); + blankSocket.Open(d->socketServer); TRequestStatus status; - nativeSocket.Accept(blankSocket, status); + d->nativeSocket.Accept(blankSocket, status); User::WaitForRequest(status); if(status.Int()) { qWarning("QSymbianSocketEnginePrivate::nativeAccept() - error %d", status.Int()); @@ -477,11 +518,12 @@ int QSymbianSocketEngine::accept() qint64 QSymbianSocketEngine::bytesAvailable() const { + Q_D(const QSymbianSocketEngine); int nbytes = 0; qint64 available = 0; // FIXME is this the right thing also for UDP? // What is expected for UDP, the length for the next packet I guess? - TInt err = nativeSocket.GetOpt(KSOReadBytesPending, KSOLSocket, nbytes); + TInt err = d->nativeSocket.GetOpt(KSOReadBytesPending, KSOLSocket, nbytes); if(err) return 0; available = (qint64) nbytes; @@ -494,34 +536,39 @@ qint64 QSymbianSocketEngine::bytesAvailable() const bool QSymbianSocketEngine::hasPendingDatagrams() const { + Q_D(const QSymbianSocketEngine); int nbytes; - TInt err = nativeSocket.GetOpt(KSOReadBytesPending,KSOLSocket, nbytes); + TInt err = d->nativeSocket.GetOpt(KSOReadBytesPending,KSOLSocket, nbytes); return err == KErrNone && nbytes > 0; //TODO: this is pretty horrible too... + // FIXME why? } qint64 QSymbianSocketEngine::pendingDatagramSize() const { + Q_D(const QSymbianSocketEngine); int nbytes; - TInt err = nativeSocket.GetOpt(KSOReadBytesPending,KSOLSocket, nbytes); + TInt err = d->nativeSocket.GetOpt(KSOReadBytesPending,KSOLSocket, nbytes); return qint64(nbytes-28); //TODO: why -28 (open C version had this)? // Why = Could it be that this is about header lengths etc? if yes // this could be pretty broken, especially for IPv6 } -qint64 QSymbianSocketEngine::nativeReceiveDatagram(char *data, qint64 maxSize, + +qint64 QSymbianSocketEngine::readDatagram(char *data, qint64 maxSize, QHostAddress *address, quint16 *port) { + Q_D(QSymbianSocketEngine); TPtr8 buffer((TUint8*)data, (int)maxSize); TInetAddr addr; TRequestStatus status; //TODO: OMG sync receive! - nativeSocket.RecvFrom(buffer, addr, 0, status); + d->nativeSocket.RecvFrom(buffer, addr, 0, status); User::WaitForRequest(status); if (status.Int()) { - setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString); + d->setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString); } else if (port || address) { - getPortAndAddress(addr, port, address); + d->getPortAndAddress(addr, port, address); } #if defined (QNATIVESOCKETENGINE_DEBUG) @@ -537,15 +584,17 @@ qint64 QSymbianSocketEngine::nativeReceiveDatagram(char *data, qint64 maxSize, return qint64(buffer.Length()); } -qint64 QSymbianSocketEngine::sendDatagram(const char *data, qint64 len, + +qint64 QSymbianSocketEngine::writeDatagram(const char *data, qint64 len, const QHostAddress &host, quint16 port) { + Q_D(QSymbianSocketEngine); TPtrC8 buffer((TUint8*)data, (int)len); TInetAddr addr; - setPortAndAddress(addr, port, host); + d->setPortAndAddress(addr, port, host); TSockXfrLength sentBytes; TRequestStatus status; //TODO: OMG sync send! - nativeSocket.SendTo(buffer, addr, 0, status, sentBytes); + d->nativeSocket.SendTo(buffer, addr, 0, status, sentBytes); User::WaitForRequest(status); TInt err = status.Int(); @@ -568,6 +617,7 @@ qint64 QSymbianSocketEngine::sendDatagram(const char *data, qint64 len, return qint64(sentBytes()); } +// FIXME check where the native socket engine called that.. bool QSymbianSocketEnginePrivate::fetchConnectionParameters() { localPort = 0; @@ -611,7 +661,8 @@ bool QSymbianSocketEnginePrivate::fetchConnectionParameters() TProtocolDesc protocol; TInt err = nativeSocket.Info(protocol); if (err) { - QAbstractSocket::UnknownSocketType; + // ? + // QAbstractSocket::UnknownSocketType; } else { switch (protocol.iProtocol) { case KProtocolInetTcp: @@ -626,13 +677,13 @@ bool QSymbianSocketEnginePrivate::fetchConnectionParameters() } } #if defined (QNATIVESOCKETENGINE_DEBUG) - QString socketProtocolStr = "UnknownProtocol"; - if (socketProtocol == QAbstractSocket::IPv4Protocol) socketProtocolStr = "IPv4Protocol"; - else if (socketProtocol == QAbstractSocket::IPv6Protocol) socketProtocolStr = "IPv6Protocol"; + QString socketProtocolStr = QLatin1String("UnknownProtocol"); + if (socketProtocol == QAbstractSocket::IPv4Protocol) socketProtocolStr = QLatin1String("IPv4Protocol"); + else if (socketProtocol == QAbstractSocket::IPv6Protocol) socketProtocolStr = QLatin1String("IPv6Protocol"); - QString socketTypeStr = "UnknownSocketType"; - if (socketType == QAbstractSocket::TcpSocket) socketTypeStr = "TcpSocket"; - else if (socketType == QAbstractSocket::UdpSocket) socketTypeStr = "UdpSocket"; + QString socketTypeStr = QLatin1String("UnknownSocketType"); + if (socketType == QAbstractSocket::TcpSocket) socketTypeStr = QLatin1String("TcpSocket"); + else if (socketType == QAbstractSocket::UdpSocket) socketTypeStr = QLatin1String("UdpSocket"); qDebug("QSymbianSocketEnginePrivate::fetchConnectionParameters() local == %s:%i," " peer == %s:%i, socket == %s - %s", @@ -645,22 +696,25 @@ bool QSymbianSocketEnginePrivate::fetchConnectionParameters() void QSymbianSocketEngine::close() { + Q_D(QSymbianSocketEngine); #if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QSymbianSocketEnginePrivate::nativeClose()"); #endif //TODO: call nativeSocket.Shutdown(EImmediate) in some cases? - nativeSocket.Close(); - QSymbianSocketManager::instance().removeSocket(nativeSocket); + d->nativeSocket.Close(); + QSymbianSocketManager::instance().removeSocket(d->nativeSocket); + + // FIXME set nativeSocket to 0 ? } qint64 QSymbianSocketEngine::write(const char *data, qint64 len) { - Q_Q(QSymbianSocketEngine); + Q_D(QSymbianSocketEngine); TPtrC8 buffer((TUint8*)data, (int)len); TSockXfrLength sentBytes; TRequestStatus status; //TODO: OMG sync send! - nativeSocket.Send(buffer, 0, status, sentBytes); + d->nativeSocket.Send(buffer, 0, status, sentBytes); User::WaitForRequest(status); TInt err = status.Int(); @@ -668,16 +722,16 @@ qint64 QSymbianSocketEngine::write(const char *data, qint64 len) switch (err) { case KErrDisconnected: sentBytes = -1; - setError(QAbstractSocket::RemoteHostClosedError, RemoteHostClosedErrorString); - q->close(); + d->setError(QAbstractSocket::RemoteHostClosedError, RemoteHostClosedErrorString); + close(); break; case KErrTooBig: - setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString); + d->setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString); break; case KErrWouldBlock: sentBytes = 0; default: - setError(QAbstractSocket::NetworkError, SendDatagramErrorString); + d->setError(QAbstractSocket::NetworkError, SendDatagramErrorString); } } @@ -693,8 +747,8 @@ qint64 QSymbianSocketEngine::write(const char *data, qint64 len) */ qint64 QSymbianSocketEngine::read(char *data, qint64 maxSize) { - Q_Q(QSymbianSocketEngine); - if (!q->isValid()) { + Q_D(QSymbianSocketEngine); + if (!isValid()) { qWarning("QSymbianSocketEnginePrivate::nativeRead: Invalid socket"); return -1; } @@ -702,7 +756,7 @@ qint64 QSymbianSocketEngine::read(char *data, qint64 maxSize) TPtr8 buffer((TUint8*)data, (int)maxSize); TSockXfrLength received = 0; TRequestStatus status; //TODO: OMG sync receive! - nativeSocket.RecvOneOrMore(buffer, 0, status, received); + d->nativeSocket.RecvOneOrMore(buffer, 0, status, received); User::WaitForRequest(status); TInt err = status.Int(); int r = received(); @@ -732,6 +786,7 @@ qint64 QSymbianSocketEngine::read(char *data, qint64 maxSize) return qint64(r); } +// FIXME wait vs select int QSymbianSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const { bool readyRead = false; @@ -826,4 +881,36 @@ bool QSymbianSocketEngine::setMulticastInterface(const QNetworkInterface &iface) return false; } +bool QSymbianSocketEnginePrivate::checkProxy(const QHostAddress &address) +{ + if (address == QHostAddress::LocalHost || address == QHostAddress::LocalHostIPv6) + return true; + +#if !defined(QT_NO_NETWORKPROXY) + QObject *parent = q_func()->parent(); + QNetworkProxy proxy; + if (QAbstractSocket *socket = qobject_cast(parent)) { + proxy = socket->proxy(); + } else if (QTcpServer *server = qobject_cast(parent)) { + proxy = server->proxy(); + } else { + // no parent -> no proxy + return true; + } + + if (proxy.type() == QNetworkProxy::DefaultProxy) + proxy = QNetworkProxy::applicationProxy(); + + if (proxy.type() != QNetworkProxy::DefaultProxy && + proxy.type() != QNetworkProxy::NoProxy) { + // QNativeSocketEngine doesn't do proxies + setError(QAbstractSocket::UnsupportedSocketOperationError, + InvalidProxyTypeString); + return false; + } +#endif + + return true; +} + QT_END_NAMESPACE diff --git a/src/network/socket/qsymbiansocketengine_p.h b/src/network/socket/qsymbiansocketengine_p.h index fd449ca..0b385a9 100644 --- a/src/network/socket/qsymbiansocketengine_p.h +++ b/src/network/socket/qsymbiansocketengine_p.h @@ -207,6 +207,8 @@ public: int nativeSelect(int timeout, bool checkRead, bool checkWrite, bool *selectForRead, bool *selectForWrite) const; + bool createNewSocket(QAbstractSocket::SocketType socketType, + QAbstractSocket::NetworkLayerProtocol socketProtocol); bool checkProxy(const QHostAddress &address); bool fetchConnectionParameters(); -- cgit v0.12 From f71a7c4ef3c4c5a02730544d93200ef96d777aa0 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Wed, 8 Dec 2010 11:49:09 +0100 Subject: QSymbianSocketEngine: More compile fixes --- src/network/socket/qsymbiansocketengine.cpp | 578 ++++++++++++++++++++++++---- src/network/socket/qsymbiansocketengine_p.h | 3 +- src/network/socket/socket.pri | 10 +- 3 files changed, 510 insertions(+), 81 deletions(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index 7957baf..43f0a36 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -61,6 +61,14 @@ # include "qtcpserver.h" #endif +#include +#include +#include + +#include "qnativesocketengine_p.h" +#include +#include + #define QNATIVESOCKETENGINE_DEBUG #if defined QNATIVESOCKETENGINE_DEBUG @@ -173,70 +181,11 @@ bool QSymbianSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType so return false; } - // FIXME Set socket to nonblocking. While we are still a QNativeSocketEngine this is done already. - // Uncomment the following when we switch to QSymbianSocketEngine. - // setOption(NonBlockingSocketOption, 1) socketDescriptor = QSymbianSocketManager::instance().addSocket(nativeSocket); return true; } -/* - Returns the value of the socket option \a opt. -*/ -int QSymbianSocketEngine::option(QAbstractSocketEngine::SocketOption opt) const -{ - Q_D(const QSymbianSocketEngine); - if (!isValid()) - return -1; - - TUint n; - TUint level = KSOLSocket; // default - - switch (opt) { - case QAbstractSocketEngine::ReceiveBufferSocketOption: - n = KSORecvBuf; - break; - case QAbstractSocketEngine::SendBufferSocketOption: - n = KSOSendBuf; - break; - case QAbstractSocketEngine::NonBlockingSocketOption: - n = KSONonBlockingIO; - break; - case QAbstractSocketEngine::BroadcastSocketOption: - return true; //symbian doesn't support or require this option - case QAbstractSocketEngine::AddressReusable: - level = KSolInetIp; - n = KSoReuseAddr; - break; - case QAbstractSocketEngine::BindExclusively: - return true; - case QAbstractSocketEngine::ReceiveOutOfBandData: - level = KSolInetTcp; - n = KSoTcpOobInline; - break; - case QAbstractSocketEngine::LowDelayOption: - level = KSolInetTcp; - n = KSoTcpNoDelay; - break; - case QAbstractSocketEngine::KeepAliveOption: - level = KSolInetTcp; - n = KSoTcpKeepAlive; - break; - default: - return -1; - } - - int v = -1; - //GetOpt() is non const - TInt err = d->nativeSocket.GetOpt(n, level, v); - if (!err) - return v; - - return -1; -} - - void QSymbianSocketEnginePrivate::setPortAndAddress(TInetAddr& nativeAddr, quint16 port, const QHostAddress &addr) { nativeAddr.SetPort(port); @@ -293,6 +242,150 @@ QSymbianSocketEngine::~QSymbianSocketEngine() // FIXME what else do we need to free? } +/*! + Initializes a QSymbianSocketEngine by creating a new socket of type \a + socketType and network layer protocol \a protocol. Returns true on + success; otherwise returns false. + + If the socket was already initialized, this function closes the + socket before reeinitializing it. + + The new socket is non-blocking, and for UDP sockets it's also + broadcast enabled. +*/ +bool QSymbianSocketEngine::initialize(QAbstractSocket::SocketType socketType, QAbstractSocket::NetworkLayerProtocol protocol) +{ + Q_D(QSymbianSocketEngine); + if (isValid()) + close(); + +#if defined(QT_NO_IPV6) + if (protocol == QAbstractSocket::IPv6Protocol) { + d->setError(QAbstractSocket::UnsupportedSocketOperationError, + d->NoIpV6ErrorString); + return false; + } +#endif + + // Create the socket + if (!d->createNewSocket(socketType, protocol)) { +#if defined (QNATIVESOCKETENGINE_DEBUG) + QString typeStr = QLatin1String("UnknownSocketType"); + if (socketType == QAbstractSocket::TcpSocket) typeStr = QLatin1String("TcpSocket"); + else if (socketType == QAbstractSocket::UdpSocket) typeStr = QLatin1String("UdpSocket"); + QString protocolStr = QLatin1String("UnknownProtocol"); + if (protocol == QAbstractSocket::IPv4Protocol) protocolStr = QLatin1String("IPv4Protocol"); + else if (protocol == QAbstractSocket::IPv6Protocol) protocolStr = QLatin1String("IPv6Protocol"); + qDebug("QNativeSocketEngine::initialize(type == %s, protocol == %s) failed: %s", + typeStr.toLatin1().constData(), protocolStr.toLatin1().constData(), d->socketErrorString.toLatin1().constData()); +#endif + return false; + } + + // Make the socket nonblocking. + if (!setOption(NonBlockingSocketOption, 1)) { + d->setError(QAbstractSocket::UnsupportedSocketOperationError, + d->NonBlockingInitFailedErrorString); + close(); + return false; + } + + // Set the broadcasting flag if it's a UDP socket. + if (socketType == QAbstractSocket::UdpSocket + && !setOption(BroadcastSocketOption, 1)) { + d->setError(QAbstractSocket::UnsupportedSocketOperationError, + d->BroadcastingInitFailedErrorString); + close(); + return false; + } + + + // Make sure we receive out-of-band data + if (socketType == QAbstractSocket::TcpSocket + && !setOption(ReceiveOutOfBandData, 1)) { + qWarning("QNativeSocketEngine::initialize unable to inline out-of-band data"); + } + + + d->socketType = socketType; + d->socketProtocol = protocol; + return true; +} + +/*! \overload + + Initializes the socket using \a socketDescriptor instead of + creating a new one. The socket type and network layer protocol are + determined automatically. The socket's state is set to \a + socketState. + + If the socket type is either TCP or UDP, it is made non-blocking. + UDP sockets are also broadcast enabled. + */ +bool QSymbianSocketEngine::initialize(int socketDescriptor, QAbstractSocket::SocketState socketState) +{ + Q_D(QSymbianSocketEngine); + + if (isValid()) + close(); + + d->socketDescriptor = socketDescriptor; + + // determine socket type and protocol + if (!d->fetchConnectionParameters()) { +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QNativeSocketEngine::initialize(socketDescriptor == %i) failed: %s", + socketDescriptor, d->socketErrorString.toLatin1().constData()); +#endif + d->socketDescriptor = -1; + return false; + } + + if (d->socketType != QAbstractSocket::UnknownSocketType) { + // Make the socket nonblocking. + if (!setOption(NonBlockingSocketOption, 1)) { + d->setError(QAbstractSocket::UnsupportedSocketOperationError, + d->NonBlockingInitFailedErrorString); + close(); + return false; + } + + // Set the broadcasting flag if it's a UDP socket. + if (d->socketType == QAbstractSocket::UdpSocket + && !setOption(BroadcastSocketOption, 1)) { + d->setError(QAbstractSocket::UnsupportedSocketOperationError, + d->BroadcastingInitFailedErrorString); + close(); + return false; + } + } + + d->socketState = socketState; + return true; +} + +/*! + Returns true if the socket is valid; otherwise returns false. A + socket is valid if it has not been successfully initialized, or if + it has been closed. +*/ +bool QSymbianSocketEngine::isValid() const +{ + Q_D(const QSymbianSocketEngine); + return d->socketDescriptor != -1; +} + + +/*! + Returns the native socket descriptor. Any use of this descriptor + stands the risk of being non-portable. +*/ +int QSymbianSocketEngine::socketDescriptor() const +{ + Q_D(const QSymbianSocketEngine); + return d->socketDescriptor; +} + /* Sets the socket option \a opt to \a v. */ @@ -340,6 +433,61 @@ bool QSymbianSocketEngine::setOption(QAbstractSocketEngine::SocketOption opt, in return (KErrNone == d->nativeSocket.SetOpt(n, level, v)); } +/* + Returns the value of the socket option \a opt. +*/ +int QSymbianSocketEngine::option(QAbstractSocketEngine::SocketOption opt) const +{ + Q_D(const QSymbianSocketEngine); + if (!isValid()) + return -1; + + TUint n; + TUint level = KSOLSocket; // default + + switch (opt) { + case QAbstractSocketEngine::ReceiveBufferSocketOption: + n = KSORecvBuf; + break; + case QAbstractSocketEngine::SendBufferSocketOption: + n = KSOSendBuf; + break; + case QAbstractSocketEngine::NonBlockingSocketOption: + n = KSONonBlockingIO; + break; + case QAbstractSocketEngine::BroadcastSocketOption: + return true; //symbian doesn't support or require this option + case QAbstractSocketEngine::AddressReusable: + level = KSolInetIp; + n = KSoReuseAddr; + break; + case QAbstractSocketEngine::BindExclusively: + return true; + case QAbstractSocketEngine::ReceiveOutOfBandData: + level = KSolInetTcp; + n = KSoTcpOobInline; + break; + case QAbstractSocketEngine::LowDelayOption: + level = KSolInetTcp; + n = KSoTcpNoDelay; + break; + case QAbstractSocketEngine::KeepAliveOption: + level = KSolInetTcp; + n = KSoTcpKeepAlive; + break; + default: + return -1; + } + + int v = -1; + //GetOpt() is non const + TInt err = d->nativeSocket.GetOpt(n, level, v); + if (!err) + return v; + + return -1; +} + bool QSymbianSocketEngine::connectToHostByName(const QString &name, quint16 port) { // FIXME for engines that support hostnames.. not for us then i guess. @@ -347,6 +495,23 @@ bool QSymbianSocketEngine::connectToHostByName(const QString &name, quint16 port return false; } +/*! + If there's a connection activity on the socket, process it. Then + notify our parent if there really was activity. +*/ +void QSymbianSocketEngine::connectionNotification() +{ + // FIXME check if we really need to do it like that in Symbian + Q_D(QSymbianSocketEngine); + Q_ASSERT(state() == QAbstractSocket::ConnectingState); + + connectToHost(d->peerAddress, d->peerPort); + if (state() != QAbstractSocket::ConnectingState) { + // we changed states + QAbstractSocketEngine::connectionNotification(); + } +} + bool QSymbianSocketEngine::connectToHost(const QHostAddress &addr, quint16 port) { @@ -359,7 +524,7 @@ bool QSymbianSocketEngine::connectToHost(const QHostAddress &addr, quint16 port) #if defined (QT_NO_IPV6) if (addr.protocol() == QAbstractSocket::IPv6Protocol) { d->setError(QAbstractSocket::UnsupportedSocketOperationError, - NoIpV6ErrorString); + d->NoIpV6ErrorString); return false; } #endif @@ -379,25 +544,25 @@ bool QSymbianSocketEngine::connectToHost(const QHostAddress &addr, quint16 port) if (err) { switch (err) { case KErrCouldNotConnect: - d->setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString); + d->setError(QAbstractSocket::ConnectionRefusedError, d->ConnectionRefusedErrorString); d->socketState = QAbstractSocket::UnconnectedState; break; case KErrTimedOut: - d->setError(QAbstractSocket::NetworkError, ConnectionTimeOutErrorString); + d->setError(QAbstractSocket::NetworkError, d->ConnectionTimeOutErrorString); break; case KErrHostUnreach: - d->setError(QAbstractSocket::NetworkError, HostUnreachableErrorString); + d->setError(QAbstractSocket::NetworkError, d->HostUnreachableErrorString); d->socketState = QAbstractSocket::UnconnectedState; break; case KErrNetUnreach: - d->setError(QAbstractSocket::NetworkError, NetworkUnreachableErrorString); + d->setError(QAbstractSocket::NetworkError, d->NetworkUnreachableErrorString); d->socketState = QAbstractSocket::UnconnectedState; break; case KErrInUse: - d->setError(QAbstractSocket::NetworkError, AddressInuseErrorString); + d->setError(QAbstractSocket::NetworkError, d->AddressInuseErrorString); break; case KErrPermissionDenied: - d->setError(QAbstractSocket::SocketAccessError, AccessErrorString); + d->setError(QAbstractSocket::SocketAccessError, d->AccessErrorString); d->socketState = QAbstractSocket::UnconnectedState; break; case KErrNotSupported: @@ -439,13 +604,13 @@ bool QSymbianSocketEngine::bind(const QHostAddress &address, quint16 port) if (err) { switch(errno) { case KErrInUse: - d->setError(QAbstractSocket::AddressInUseError, AddressInuseErrorString); + d->setError(QAbstractSocket::AddressInUseError, d->AddressInuseErrorString); break; case KErrPermissionDenied: - d->setError(QAbstractSocket::SocketAccessError, AddressProtectedErrorString); + d->setError(QAbstractSocket::SocketAccessError, d->AddressProtectedErrorString); break; case KErrNotSupported: - d->setError(QAbstractSocket::UnsupportedSocketOperationError, OperationUnsupportedErrorString); + d->setError(QAbstractSocket::UnsupportedSocketOperationError, d->OperationUnsupportedErrorString); break; default: break; @@ -477,7 +642,7 @@ bool QSymbianSocketEngine::listen() switch (errno) { case KErrInUse: d->setError(QAbstractSocket::AddressInUseError, - PortInuseErrorString); + d->PortInuseErrorString); break; default: break; @@ -566,7 +731,7 @@ qint64 QSymbianSocketEngine::readDatagram(char *data, qint64 maxSize, User::WaitForRequest(status); if (status.Int()) { - d->setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString); + d->setError(QAbstractSocket::NetworkError, d->ReceiveDatagramErrorString); } else if (port || address) { d->getPortAndAddress(addr, port, address); } @@ -601,10 +766,10 @@ qint64 QSymbianSocketEngine::writeDatagram(const char *data, qint64 len, if (err) { switch (err) { case KErrTooBig: - setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString); + d->setError(QAbstractSocket::DatagramTooLargeError, d->DatagramTooLargeErrorString); break; default: - setError(QAbstractSocket::NetworkError, SendDatagramErrorString); + d->setError(QAbstractSocket::NetworkError, d->SendDatagramErrorString); } } @@ -722,16 +887,16 @@ qint64 QSymbianSocketEngine::write(const char *data, qint64 len) switch (err) { case KErrDisconnected: sentBytes = -1; - d->setError(QAbstractSocket::RemoteHostClosedError, RemoteHostClosedErrorString); + d->setError(QAbstractSocket::RemoteHostClosedError, d->RemoteHostClosedErrorString); close(); break; case KErrTooBig: - d->setError(QAbstractSocket::DatagramTooLargeError, DatagramTooLargeErrorString); + d->setError(QAbstractSocket::DatagramTooLargeError, d->DatagramTooLargeErrorString); break; case KErrWouldBlock: sentBytes = 0; default: - d->setError(QAbstractSocket::NetworkError, SendDatagramErrorString); + d->setError(QAbstractSocket::NetworkError, d->SendDatagramErrorString); } } @@ -913,4 +1078,265 @@ bool QSymbianSocketEnginePrivate::checkProxy(const QHostAddress &address) return true; } +// FIXME this is also in QNativeSocketEngine, unify it +/*! \internal + + Sets the error and error string if not set already. The only + interesting error is the first one that occurred, and not the last + one. +*/ +void QSymbianSocketEnginePrivate::setError(QAbstractSocket::SocketError error, ErrorString errorString) const +{ + if (hasSetSocketError) { + // Only set socket errors once for one engine; expect the + // socket to recreate its engine after an error. Note: There's + // one exception: SocketError(11) bypasses this as it's purely + // a temporary internal error condition. + // Another exception is the way the waitFor*() functions set + // an error when a timeout occurs. After the call to setError() + // they reset the hasSetSocketError to false + return; + } + if (error != QAbstractSocket::SocketError(11)) + hasSetSocketError = true; + + socketError = error; + + switch (errorString) { + case NonBlockingInitFailedErrorString: + socketErrorString = QSymbianSocketEngine::tr("Unable to initialize non-blocking socket"); + break; + case BroadcastingInitFailedErrorString: + socketErrorString = QSymbianSocketEngine::tr("Unable to initialize broadcast socket"); + break; + case NoIpV6ErrorString: + socketErrorString = QSymbianSocketEngine::tr("Attempt to use IPv6 socket on a platform with no IPv6 support"); + break; + case RemoteHostClosedErrorString: + socketErrorString = QSymbianSocketEngine::tr("The remote host closed the connection"); + break; + case TimeOutErrorString: + socketErrorString = QSymbianSocketEngine::tr("Network operation timed out"); + break; + case ResourceErrorString: + socketErrorString = QSymbianSocketEngine::tr("Out of resources"); + break; + case OperationUnsupportedErrorString: + socketErrorString = QSymbianSocketEngine::tr("Unsupported socket operation"); + break; + case ProtocolUnsupportedErrorString: + socketErrorString = QSymbianSocketEngine::tr("Protocol type not supported"); + break; + case InvalidSocketErrorString: + socketErrorString = QSymbianSocketEngine::tr("Invalid socket descriptor"); + break; + case HostUnreachableErrorString: + socketErrorString = QSymbianSocketEngine::tr("Host unreachable"); + break; + case NetworkUnreachableErrorString: + socketErrorString = QSymbianSocketEngine::tr("Network unreachable"); + break; + case AccessErrorString: + socketErrorString = QSymbianSocketEngine::tr("Permission denied"); + break; + case ConnectionTimeOutErrorString: + socketErrorString = QSymbianSocketEngine::tr("Connection timed out"); + break; + case ConnectionRefusedErrorString: + socketErrorString = QSymbianSocketEngine::tr("Connection refused"); + break; + case AddressInuseErrorString: + socketErrorString = QSymbianSocketEngine::tr("The bound address is already in use"); + break; + case AddressNotAvailableErrorString: + socketErrorString = QSymbianSocketEngine::tr("The address is not available"); + break; + case AddressProtectedErrorString: + socketErrorString = QSymbianSocketEngine::tr("The address is protected"); + break; + case DatagramTooLargeErrorString: + socketErrorString = QSymbianSocketEngine::tr("Datagram was too large to send"); + break; + case SendDatagramErrorString: + socketErrorString = QSymbianSocketEngine::tr("Unable to send a message"); + break; + case ReceiveDatagramErrorString: + socketErrorString = QSymbianSocketEngine::tr("Unable to receive a message"); + break; + case WriteErrorString: + socketErrorString = QSymbianSocketEngine::tr("Unable to write"); + break; + case ReadErrorString: + socketErrorString = QSymbianSocketEngine::tr("Network error"); + break; + case PortInuseErrorString: + socketErrorString = QSymbianSocketEngine::tr("Another socket is already listening on the same port"); + break; + case NotSocketErrorString: + socketErrorString = QSymbianSocketEngine::tr("Operation on non-socket"); + break; + case InvalidProxyTypeString: + socketErrorString = QSymbianSocketEngine::tr("The proxy type is invalid for this operation"); + break; + case UnknownSocketErrorString: + socketErrorString = QSymbianSocketEngine::tr("Unknown error"); + break; + } +} + +class QReadNotifier : public QSocketNotifier +{ +public: + QReadNotifier(int fd, QSymbianSocketEngine *parent) + : QSocketNotifier(fd, QSocketNotifier::Read, parent) + { engine = parent; } +protected: + QSymbianSocketEngine *engine; +}; + +bool QSymbianSocketEngine::isReadNotificationEnabled() const +{ + Q_D(const QSymbianSocketEngine); + // TODO + return d->readNotifier && d->readNotifier->isEnabled(); +} + +void QSymbianSocketEngine::setReadNotificationEnabled(bool enable) +{ + Q_D(QSymbianSocketEngine); + // TODO + if (d->readNotifier) { + d->readNotifier->setEnabled(enable); + } else if (enable && d->threadData->eventDispatcher) { + d->readNotifier = new QReadNotifier(d->socketDescriptor, this); + d->readNotifier->setEnabled(true); + } +} + + +class QWriteNotifier : public QSocketNotifier +{ +public: + QWriteNotifier(int fd, QSymbianSocketEngine *parent) + : QSocketNotifier(fd, QSocketNotifier::Read, parent) + { engine = parent; } +protected: + QSymbianSocketEngine *engine; +}; + +bool QSymbianSocketEngine::isWriteNotificationEnabled() const +{ + Q_D(const QSymbianSocketEngine); + // TODO + return d->writeNotifier && d->writeNotifier->isEnabled(); +} + +void QSymbianSocketEngine::setWriteNotificationEnabled(bool enable) +{ + Q_D(QSymbianSocketEngine); + // TODO + if (d->writeNotifier) { + d->writeNotifier->setEnabled(enable); + } else if (enable && d->threadData->eventDispatcher) { + d->writeNotifier = new QWriteNotifier(d->socketDescriptor, this); + d->writeNotifier->setEnabled(true); + } +} + +// FIXME do we really need this for symbian? +bool QSymbianSocketEngine::isExceptionNotificationEnabled() const +{ +// Q_D(const QSymbianSocketEngine); +// // TODO +// return d->exceptNotifier && d->exceptNotifier->isEnabled(); + return false; +} + +// FIXME do we really need this for symbian? +void QSymbianSocketEngine::setExceptionNotificationEnabled(bool enable) +{ + Q_D(QSymbianSocketEngine); + // TODO +// if (d->exceptNotifier) { +// d->exceptNotifier->setEnabled(enable); +// } else if (enable && d->threadData->eventDispatcher) { +// d->exceptNotifier = new QExceptionNotifier(d->socketDescriptor, this); +// d->exceptNotifier->setEnabled(true); +// } +} + +bool QSymbianSocketEngine::waitForRead(int msecs, bool *timedOut) +{ + Q_D(const QSymbianSocketEngine); + + if (timedOut) + *timedOut = false; + + int ret = d->nativeSelect(msecs, true); + if (ret == 0) { + if (timedOut) + *timedOut = true; + d->setError(QAbstractSocket::SocketTimeoutError, + d->TimeOutErrorString); + d->hasSetSocketError = false; // A timeout error is temporary in waitFor functions + return false; + } else if (state() == QAbstractSocket::ConnectingState) { + connectToHost(d->peerAddress, d->peerPort); + } + + return ret > 0; +} + +bool QSymbianSocketEngine::waitForWrite(int msecs, bool *timedOut) +{ + Q_D(QSymbianSocketEngine); + + if (timedOut) + *timedOut = false; + + int ret = d->nativeSelect(msecs, false); + + if (ret == 0) { + if (timedOut) + *timedOut = true; + d->setError(QAbstractSocket::SocketTimeoutError, + d->TimeOutErrorString); + d->hasSetSocketError = false; // A timeout error is temporary in waitFor functions + return false; + } else if (state() == QAbstractSocket::ConnectingState) { + connectToHost(d->peerAddress, d->peerPort); + } + + return ret > 0; +} + +bool QSymbianSocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWrite, + bool checkRead, bool checkWrite, + int msecs, bool *timedOut) +{ + Q_D(QSymbianSocketEngine); + + int ret = d->nativeSelect(msecs, checkRead, checkWrite, readyToRead, readyToWrite); + + if (ret == 0) { + if (timedOut) + *timedOut = true; + d->setError(QAbstractSocket::SocketTimeoutError, + d->TimeOutErrorString); + d->hasSetSocketError = false; // A timeout error is temporary in waitFor functions + return false; + } else if (state() == QAbstractSocket::ConnectingState) { + connectToHost(d->peerAddress, d->peerPort); + } + + return ret > 0; +} + +qint64 QSymbianSocketEngine::bytesToWrite() const +{ + // This is what the QNativeSocketEngine does + return 0; +} + + QT_END_NAMESPACE diff --git a/src/network/socket/qsymbiansocketengine_p.h b/src/network/socket/qsymbiansocketengine_p.h index 0b385a9..0c8bc53 100644 --- a/src/network/socket/qsymbiansocketengine_p.h +++ b/src/network/socket/qsymbiansocketengine_p.h @@ -165,6 +165,7 @@ public: QSocketNotifier *readNotifier, *writeNotifier, *exceptNotifier; + // FIXME this is duplicated from qnativesocketengine_p.h enum ErrorString { NonBlockingInitFailedErrorString, BroadcastingInitFailedErrorString, @@ -194,13 +195,13 @@ public: UnknownSocketErrorString = -1 }; + void setError(QAbstractSocket::SocketError error, ErrorString errorString) const; #ifdef Q_OS_SYMBIAN void getPortAndAddress(const TInetAddr& a, quint16 *port, QHostAddress *addr); void setPortAndAddress(TInetAddr& nativeAddr, quint16 port, const QHostAddress &addr); void setError(TInt symbianError); #endif - void setError(QAbstractSocket::SocketError error, ErrorString errorString) const; // FIXME int nativeSelect(int timeout, bool selectForRead) const; diff --git a/src/network/socket/socket.pri b/src/network/socket/socket.pri index 3356cdd..3eb54a2 100644 --- a/src/network/socket/socket.pri +++ b/src/network/socket/socket.pri @@ -1,7 +1,6 @@ # Qt network socket HEADERS += socket/qabstractsocketengine_p.h \ - socket/qnativesocketengine_p.h \ socket/qhttpsocketengine_p.h \ socket/qsocks5socketengine_p.h \ socket/qabstractsocket.h \ @@ -15,7 +14,6 @@ HEADERS += socket/qabstractsocketengine_p.h \ socket/qlocalsocket_p.h SOURCES += socket/qabstractsocketengine.cpp \ - socket/qnativesocketengine.cpp \ socket/qhttpsocketengine.cpp \ socket/qsocks5socketengine.cpp \ socket/qabstractsocket.cpp \ @@ -25,10 +23,14 @@ SOURCES += socket/qabstractsocketengine.cpp \ socket/qlocalsocket.cpp \ socket/qlocalserver.cpp -unix:!symbian:SOURCES += socket/qnativesocketengine_unix.cpp - +# On Symbian we use QSymbianSocketEngine symbian:SOURCES += socket/qsymbiansocketengine.cpp symbian:HEADERS += socket/qsymbiansocketengine_p.h +# On others we use QNativeSocketEngine +!symbian:SOURCES += socket/qnativesocketengine.cpp +!symbian:HEADERS += socket/qnativesocketengine_p.h + +unix:!symbian:SOURCES += socket/qnativesocketengine_unix.cpp unix:SOURCES += \ socket/qlocalsocket_unix.cpp \ -- cgit v0.12 From fc3f909c0cbbe15f2079edefe66ce52eb127a326 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Wed, 8 Dec 2010 12:14:26 +0100 Subject: QSymbianSocketEngine: Always support IPv6 --- src/network/kernel/qnetworkproxy_symbian.cpp | 17 +++++++------ src/network/socket/qsymbiansocketengine.cpp | 37 +--------------------------- 2 files changed, 11 insertions(+), 43 deletions(-) diff --git a/src/network/kernel/qnetworkproxy_symbian.cpp b/src/network/kernel/qnetworkproxy_symbian.cpp index 62266d1..7f53b4d 100644 --- a/src/network/kernel/qnetworkproxy_symbian.cpp +++ b/src/network/kernel/qnetworkproxy_symbian.cpp @@ -48,14 +48,17 @@ QT_BEGIN_NAMESPACE QList QNetworkProxyFactory::systemProxyForQuery(const QNetworkProxyQuery &) { // TODO: Get the current QNetworkSession which has the Symbian RConnection we use - // I am wondering if we already have a connected QNetworkSession when the code - // is run that retrieves the proxy (for QNetworkAccessManager it's somewhere called - // from createRequest() which might be too early...) - - // TODO: Get the proxy from that RConnection + // I am wondering if we already have a connected QNetworkSession when the code + // is run that retrieves the proxy (for QNetworkAccessManager it's somewhere called + // from createRequest() which might be too early...) - // See http://bugreports.qt.nokia.com/browse/QTBUG-13857 and http://bugreports.qt.nokia.com/browse/QTBUG-11016 - // and the mails we have received. + // TODO: Get the proxy from that RConnection + + // The QNetworkProxyQuery could have a QNetworkSession and then take the RConnection + // from there. If it does not have one, we have to use the "global RConnection". + + // See http://bugreports.qt.nokia.com/browse/QTBUG-13857 and http://bugreports.qt.nokia.com/browse/QTBUG-11016 + // and the mails we have received. // Default case: No network proxy found/needed return QList() << QNetworkProxy::NoProxy; diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index 43f0a36..a937f7c 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -49,9 +49,7 @@ #include "qnetworkinterface.h" #include #include -#ifndef QT_NO_IPV6IFNAME #include -#endif #include @@ -112,7 +110,6 @@ static QByteArray qt_prettyDebug(const char *data, int len, int maxSize) void QSymbianSocketEnginePrivate::getPortAndAddress(const TInetAddr& a, quint16 *port, QHostAddress *addr) { -#if !defined(QT_NO_IPV6) if (a.Family() == KAfInet6) { Q_IPV6ADDR tmp; memcpy(&tmp, a.Ip6Address().u.iAddr8, sizeof(tmp)); @@ -120,21 +117,18 @@ void QSymbianSocketEnginePrivate::getPortAndAddress(const TInetAddr& a, quint16 QHostAddress tmpAddress; tmpAddress.setAddress(tmp); *addr = tmpAddress; -#ifndef QT_NO_IPV6IFNAME TPckgBuf query; query().iSrcAddr = a; TInt err = nativeSocket.GetOpt(KSoInetIfQueryBySrcAddr, KSolInetIfQuery, query); if(!err) addr->setScopeId(qt_TDesC2QString(query().iName)); else -#endif addr->setScopeId(QString::number(a.Scope())); } if (port) *port = a.Port(); return; } -#endif if (port) *port = a.Port(); if (addr) { @@ -152,12 +146,7 @@ bool QSymbianSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType so QAbstractSocket::NetworkLayerProtocol socketProtocol) { Q_Q(QSymbianSocketEngine); -#ifndef QT_NO_IPV6 TUint family = (socketProtocol == QAbstractSocket::IPv6Protocol) ? KAfInet6 : KAfInet; -#else - Q_UNUSED(socketProtocol); - TUint family = KAfInet; -#endif TUint type = (socketType == QAbstractSocket::UdpSocket) ? KSockDatagram : KSockStream; TUint protocol = (socketType == QAbstractSocket::UdpSocket) ? KProtocolInetUdp : KProtocolInetTcp; TInt err = nativeSocket.Open(socketServer, family, type, protocol, *connection); @@ -189,9 +178,7 @@ bool QSymbianSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType so void QSymbianSocketEnginePrivate::setPortAndAddress(TInetAddr& nativeAddr, quint16 port, const QHostAddress &addr) { nativeAddr.SetPort(port); -#if !defined(QT_NO_IPV6) if (addr.protocol() == QAbstractSocket::IPv6Protocol) { -#ifndef QT_NO_IPV6IFNAME TPckgBuf query; query().iName = qt_QString2TPtrC(addr.scopeId()); TInt err = nativeSocket.GetOpt(KSoInetIfQueryByName, KSolInetIfQuery, query); @@ -199,16 +186,11 @@ void QSymbianSocketEnginePrivate::setPortAndAddress(TInetAddr& nativeAddr, quint nativeAddr.SetScope(query().iIndex); else nativeAddr.SetScope(0); -#else - nativeAddr.SetScope(addr.scopeId().toInt()); -#endif Q_IPV6ADDR ip6 = addr.toIPv6Address(); TIp6Addr v6addr; memcpy(v6addr.u.iAddr8, ip6.c, 16); nativeAddr.SetAddress(v6addr); - } else -#endif - if (addr.protocol() == QAbstractSocket::IPv4Protocol) { + } else if (addr.protocol() == QAbstractSocket::IPv4Protocol) { nativeAddr.SetAddress(addr.toIPv4Address()); } else { qWarning("unsupported network protocol (%d)", addr.protocol()); @@ -259,14 +241,6 @@ bool QSymbianSocketEngine::initialize(QAbstractSocket::SocketType socketType, QA if (isValid()) close(); -#if defined(QT_NO_IPV6) - if (protocol == QAbstractSocket::IPv6Protocol) { - d->setError(QAbstractSocket::UnsupportedSocketOperationError, - d->NoIpV6ErrorString); - return false; - } -#endif - // Create the socket if (!d->createNewSocket(socketType, protocol)) { #if defined (QNATIVESOCKETENGINE_DEBUG) @@ -521,13 +495,6 @@ bool QSymbianSocketEngine::connectToHost(const QHostAddress &addr, quint16 port) qDebug("QSymbianSocketEngine::connectToHost() : %d ", d->socketDescriptor); #endif -#if defined (QT_NO_IPV6) - if (addr.protocol() == QAbstractSocket::IPv6Protocol) { - d->setError(QAbstractSocket::UnsupportedSocketOperationError, - d->NoIpV6ErrorString); - return false; - } -#endif if (!d->checkProxy(addr)) return false; @@ -808,11 +775,9 @@ bool QSymbianSocketEnginePrivate::fetchConnectionParameters() case KAfInet: socketProtocol = QAbstractSocket::IPv4Protocol; break; -#if !defined (QT_NO_IPV6) case KAfInet6: socketProtocol = QAbstractSocket::IPv6Protocol; break; -#endif default: socketProtocol = QAbstractSocket::UnknownNetworkLayerProtocol; break; -- cgit v0.12 From 0975f046497deccd57b59aacded3ffc3c3c912f6 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Wed, 8 Dec 2010 12:44:51 +0100 Subject: QNativeSocketEngine: Remove symbian code --- src/network/socket/qnativesocketengine_p.h | 7 -- src/network/socket/qnativesocketengine_unix.cpp | 105 +----------------------- 2 files changed, 1 insertion(+), 111 deletions(-) diff --git a/src/network/socket/qnativesocketengine_p.h b/src/network/socket/qnativesocketengine_p.h index 1f13433..b122722 100644 --- a/src/network/socket/qnativesocketengine_p.h +++ b/src/network/socket/qnativesocketengine_p.h @@ -60,13 +60,6 @@ # include #endif -#ifdef Q_OS_SYMBIAN -#include -#include -#include -#include -#endif - QT_BEGIN_NAMESPACE // Use our own defines and structs which we know are correct diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp index aa55009..47a9084 100644 --- a/src/network/socket/qnativesocketengine_unix.cpp +++ b/src/network/socket/qnativesocketengine_unix.cpp @@ -65,12 +65,7 @@ #include #endif -#ifdef Q_OS_SYMBIAN // ### TODO: Are these headers right? -#include -#include -#else #include -#endif QT_BEGIN_NAMESPACE @@ -1049,11 +1044,7 @@ void QNativeSocketEnginePrivate::nativeClose() qDebug("QNativeSocketEngine::nativeClose()"); #endif -#ifdef Q_OS_SYMBIAN - ::close(socketDescriptor); -#else - qt_safe_close(socketDescriptor); -#endif + qt_safe_close(socketDescriptor); } qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len) @@ -1064,12 +1055,7 @@ qint64 QNativeSocketEnginePrivate::nativeWrite(const char *data, qint64 len) qt_ignore_sigpipe(); ssize_t writtenBytes; -#ifdef Q_OS_SYMBIAN - // Symbian does not support signals natively and Open C returns EINTR when moving to offline - writtenBytes = ::write(socketDescriptor, data, len); -#else writtenBytes = qt_safe_write(socketDescriptor, data, len); -#endif if (writtenBytes < 0) { switch (errno) { @@ -1109,11 +1095,7 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize) } ssize_t r = 0; -#ifdef Q_OS_SYMBIAN - r = ::read(socketDescriptor, data, maxSize); -#else r = qt_safe_read(socketDescriptor, data, maxSize); -#endif if (r < 0) { r = -1; @@ -1130,9 +1112,6 @@ qint64 QNativeSocketEnginePrivate::nativeRead(char *data, qint64 maxSize) case EIO: //error string is now set in read(), not here in nativeRead() break; -#ifdef Q_OS_SYMBIAN - case EPIPE: -#endif case ECONNRESET: #if defined(Q_OS_VXWORKS) case ESHUTDOWN: @@ -1163,40 +1142,11 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) co tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; -#ifdef Q_OS_SYMBIAN - fd_set fdexception; - FD_ZERO(&fdexception); - FD_SET(socketDescriptor, &fdexception); -#endif - int retval; if (selectForRead) -#ifdef Q_OS_SYMBIAN - retval = ::select(socketDescriptor + 1, &fds, 0, &fdexception, timeout < 0 ? 0 : &tv); -#else retval = qt_safe_select(socketDescriptor + 1, &fds, 0, 0, timeout < 0 ? 0 : &tv); -#endif else -#ifdef Q_OS_SYMBIAN - retval = ::select(socketDescriptor + 1, 0, &fds, &fdexception, timeout < 0 ? 0 : &tv); -#else retval = qt_safe_select(socketDescriptor + 1, 0, &fds, 0, timeout < 0 ? 0 : &tv); -#endif - - -#ifdef Q_OS_SYMBIAN - bool selectForExec = false; - if(retval != 0) { - if(retval < 0) { - qWarning("nativeSelect(....) returned < 0 for socket %d", socketDescriptor); - } - selectForExec = FD_ISSET(socketDescriptor, &fdexception); - } - if(selectForExec) { - qWarning("nativeSelect (selectForRead %d, retVal %d, errno %d) Unexpected exception for fd %d", - selectForRead, retval, errno, socketDescriptor); - } -#endif return retval; } @@ -1214,65 +1164,12 @@ int QNativeSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool c if (checkWrite) FD_SET(socketDescriptor, &fdwrite); -#ifdef Q_OS_SYMBIAN - fd_set fdexception; - FD_ZERO(&fdexception); - FD_SET(socketDescriptor, &fdexception); -#endif - struct timeval tv; tv.tv_sec = timeout / 1000; tv.tv_usec = (timeout % 1000) * 1000; int ret; -#ifndef Q_OS_SYMBIAN ret = qt_safe_select(socketDescriptor + 1, &fdread, &fdwrite, 0, timeout < 0 ? 0 : &tv); -#else - QElapsedTimer timer; - timer.start(); - - do { - ret = ::select(socketDescriptor + 1, &fdread, &fdwrite, &fdexception, timeout < 0 ? 0 : &tv); - bool selectForExec = false; - if(ret != 0) { - if(ret < 0) { - qWarning("nativeSelect(....) returned < 0 for socket %d", socketDescriptor); - } - selectForExec = FD_ISSET(socketDescriptor, &fdexception); - } - if(selectForExec) { - qWarning("nativeSelect (checkRead %d, checkWrite %d, ret %d, errno %d): Unexpected expectfds ready in fd %d", - checkRead, checkWrite, ret, errno, socketDescriptor); - if (checkWrite){ - FD_CLR(socketDescriptor, &fdread); - FD_SET(socketDescriptor, &fdwrite); - } else if (checkRead) - FD_SET(socketDescriptor, &fdread); - - - if ((ret == -1) && ( errno == ECONNREFUSED || errno == EPIPE )) - ret = 1; - - } - - if (ret != -1 || errno != EINTR) { - break; - } - - if (timeout > 0) { - // recalculate the timeout - int t = timeout - timer.elapsed(); - if (t < 0) { - // oops, timeout turned negative? - ret = -1; - break; - } - - tv.tv_sec = t / 1000; - tv.tv_usec = (t % 1000) * 1000; - } - } while (true); -#endif if (ret <= 0) return ret; -- cgit v0.12 From 4b31d0c75755a57667d5d76e44e4b8653aa15219 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Wed, 8 Dec 2010 12:50:50 +0100 Subject: Symbian: Enable IPv6 again. The native QSymbianSocketEngine supports IPv6 just fine. This reverts commit 0c7d5d106152924dedd822da8c90d9f3247a9947. --- configure | 8 ++------ tools/configure/configureapp.cpp | 4 ---- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/configure b/configure index 05b5629..401299b 100755 --- a/configure +++ b/configure @@ -6463,13 +6463,9 @@ fi # find if the platform supports IPv6 if [ "$CFG_IPV6" != "no" ]; then - # - # We accidently enabled IPv6 for Qt Symbian in 4.6.x. However the underlying OpenC does not fully support IPV6. - # Therefore for 4.7.1 and following we disable it until OpenC either supports it or we have the native Qt - # symbian socket engine. - # if [ "$XPLATFORM_SYMBIAN" = "yes" ]; then - CFG_IPV6=no + #IPV6 should always be enabled for Symbian release + CFG_IPV6=yes elif "$unixtests/compile.test" "$XQMAKESPEC" "$QMAKE_CONFIG" $OPT_VERBOSE "$relpath" "$outpath" config.tests/unix/ipv6 "IPv6" $L_FLAGS $I_FLAGS $l_FLAGS $MAC_CONFIG_TEST_COMMANDLINE; then CFG_IPV6=yes else diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp index 479fd4c..f4a558d 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -1522,10 +1522,6 @@ void Configure::applySpecSpecifics() dictionary[ "QT3SUPPORT" ] = "no"; dictionary[ "OPENGL" ] = "no"; dictionary[ "OPENSSL" ] = "yes"; - // We accidently enabled IPv6 for Qt Symbian in 4.6.x. However the underlying OpenC does not fully support IPV6. - // Therefore for 4.7.1 and following we disable it until OpenC either supports it or we have the native Qt - // symbian socket engine. - dictionary[ "IPV6" ] = "no"; dictionary[ "STL" ] = "yes"; dictionary[ "EXCEPTIONS" ] = "yes"; dictionary[ "RTTI" ] = "yes"; -- cgit v0.12 From f237b3ff201c271c386c912f496069825fd5cc12 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Wed, 8 Dec 2010 13:02:16 +0100 Subject: Symbian: Also force IPv6 on Windows configure.exe --- tools/configure/configureapp.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/configure/configureapp.cpp b/tools/configure/configureapp.cpp index f4a558d..62e7859 100644 --- a/tools/configure/configureapp.cpp +++ b/tools/configure/configureapp.cpp @@ -1522,6 +1522,8 @@ void Configure::applySpecSpecifics() dictionary[ "QT3SUPPORT" ] = "no"; dictionary[ "OPENGL" ] = "no"; dictionary[ "OPENSSL" ] = "yes"; + // On Symbian we now always will have IPv6 with no chance to disable it + dictionary[ "IPV6" ] = "yes"; dictionary[ "STL" ] = "yes"; dictionary[ "EXCEPTIONS" ] = "yes"; dictionary[ "RTTI" ] = "yes"; -- cgit v0.12 From 664bd5adea54a2235414878d9cc4f1197fa2bd53 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Wed, 8 Dec 2010 13:06:14 +0000 Subject: Fix compile errors including qnativesocketengine_p.h causes link errors Reviewed-by: Markus Goetz --- src/network/socket/qabstractsocket_p.h | 2 +- src/network/socket/qlocalserver_p.h | 2 +- src/network/socket/qlocalsocket_p.h | 2 +- src/network/socket/qsymbiansocketengine.cpp | 1 - src/network/socket/qsymbiansocketengine_p.h | 2 -- src/network/socket/qtcpserver.cpp | 2 +- 6 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/network/socket/qabstractsocket_p.h b/src/network/socket/qabstractsocket_p.h index 8ca83fc..732d609 100644 --- a/src/network/socket/qabstractsocket_p.h +++ b/src/network/socket/qabstractsocket_p.h @@ -59,7 +59,7 @@ #include "QtCore/qtimer.h" #include "private/qringbuffer_p.h" #include "private/qiodevice_p.h" -#include "private/qnativesocketengine_p.h" +#include "private/qabstractsocketengine_p.h" #include "qnetworkproxy.h" QT_BEGIN_NAMESPACE diff --git a/src/network/socket/qlocalserver_p.h b/src/network/socket/qlocalserver_p.h index 4f92b64..e9c8563 100644 --- a/src/network/socket/qlocalserver_p.h +++ b/src/network/socket/qlocalserver_p.h @@ -65,7 +65,7 @@ # include # include #else -# include +# include # include #endif diff --git a/src/network/socket/qlocalsocket_p.h b/src/network/socket/qlocalsocket_p.h index 57ca3c2..7b912fb 100644 --- a/src/network/socket/qlocalsocket_p.h +++ b/src/network/socket/qlocalsocket_p.h @@ -67,7 +67,7 @@ # include "private/qringbuffer_p.h" # include #else -# include "private/qnativesocketengine_p.h" +# include "private/qabstractsocketengine_p.h" # include # include # include diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index a937f7c..1d2a11b 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -63,7 +63,6 @@ #include #include -#include "qnativesocketengine_p.h" #include #include diff --git a/src/network/socket/qsymbiansocketengine_p.h b/src/network/socket/qsymbiansocketengine_p.h index 0c8bc53..3111442 100644 --- a/src/network/socket/qsymbiansocketengine_p.h +++ b/src/network/socket/qsymbiansocketengine_p.h @@ -154,14 +154,12 @@ public: ~QSymbianSocketEnginePrivate(); int socketDescriptor; -#ifdef Q_OS_SYMBIAN mutable RSocket nativeSocket; // From QtCore: RSocketServ& socketServer; // From QtCore, check lifetime issues, also should be pulling this out of a QNetworkSession somehow: RConnection *connection; mutable RTimer selectTimer; -#endif QSocketNotifier *readNotifier, *writeNotifier, *exceptNotifier; diff --git a/src/network/socket/qtcpserver.cpp b/src/network/socket/qtcpserver.cpp index 0640c7c..642983f 100644 --- a/src/network/socket/qtcpserver.cpp +++ b/src/network/socket/qtcpserver.cpp @@ -105,7 +105,7 @@ #include "qhostaddress.h" #include "qlist.h" #include "qpointer.h" -#include "qnativesocketengine_p.h" +#include "qabstractsocketengine_p.h" #include "qtcpserver.h" #include "qtcpsocket.h" #include "qnetworkproxy.h" -- cgit v0.12 From a50a764095f4894790dcb5bdfeb845ca65da7501 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Wed, 8 Dec 2010 14:38:19 +0100 Subject: Remove more Q_OS_SYMBIAN stuff from network code --- src/network/kernel/qhostinfo_unix.cpp | 13 +---- src/network/socket/qnativesocketengine_unix.cpp | 64 +++---------------------- src/network/socket/qsymbiansocketengine_p.h | 2 - 3 files changed, 7 insertions(+), 72 deletions(-) diff --git a/src/network/kernel/qhostinfo_unix.cpp b/src/network/kernel/qhostinfo_unix.cpp index 5ca15a3..cb1ec43 100644 --- a/src/network/kernel/qhostinfo_unix.cpp +++ b/src/network/kernel/qhostinfo_unix.cpp @@ -147,7 +147,7 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) if (address.setAddress(hostName)) { // Reverse lookup // Reverse lookups using getnameinfo are broken on darwin, use gethostbyaddr instead. -#if !defined (QT_NO_GETADDRINFO) && !defined (Q_OS_DARWIN) && !defined (Q_OS_SYMBIAN) +#if !defined (QT_NO_GETADDRINFO) && !defined (Q_OS_DARWIN) sockaddr_in sa4; #ifndef QT_NO_IPV6 sockaddr_in6 sa6; @@ -208,23 +208,12 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) #ifdef Q_ADDRCONFIG hints.ai_flags = Q_ADDRCONFIG; #endif -#ifdef Q_OS_SYMBIAN -# ifdef QHOSTINFO_DEBUG - qDebug() << "Setting flags: 'hints.ai_flags &= AI_V4MAPPED | AI_ALL'"; -# endif -#endif int result = getaddrinfo(aceHostname.constData(), 0, &hints, &res); # ifdef Q_ADDRCONFIG if (result == EAI_BADFLAGS) { // if the lookup failed with AI_ADDRCONFIG set, try again without it hints.ai_flags = 0; -#ifdef Q_OS_SYMBIAN -# ifdef QHOSTINFO_DEBUG - qDebug() << "Setting flags: 'hints.ai_flags &= AI_V4MAPPED | AI_ALL'"; -# endif - hints.ai_flags &= AI_V4MAPPED | AI_ALL; -#endif result = getaddrinfo(aceHostname.constData(), 0, &hints, &res); } # endif diff --git a/src/network/socket/qnativesocketengine_unix.cpp b/src/network/socket/qnativesocketengine_unix.cpp index 47a9084..1aaa6e6 100644 --- a/src/network/socket/qnativesocketengine_unix.cpp +++ b/src/network/socket/qnativesocketengine_unix.cpp @@ -169,11 +169,8 @@ bool QNativeSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType soc int protocol = AF_INET; #endif int type = (socketType == QAbstractSocket::UdpSocket) ? SOCK_DGRAM : SOCK_STREAM; -#ifdef Q_OS_SYMBIAN - int socket = ::socket(protocol, type, 0); -#else + int socket = qt_safe_socket(protocol, type, 0); -#endif if (socket <= 0) { switch (errno) { @@ -318,11 +315,9 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt } #else // Q_OS_VXWORKS int onoff = 1; -#ifdef Q_OS_SYMBIAN - if (::ioctl(socketDescriptor, FIONBIO, &onoff) < 0) { -#else + if (qt_safe_ioctl(socketDescriptor, FIONBIO, &onoff) < 0) { -#endif + #ifdef QNATIVESOCKETENGINE_DEBUG perror("QNativeSocketEnginePrivate::setOption(): ioctl(FIONBIO, 1) failed"); #endif @@ -332,7 +327,7 @@ bool QNativeSocketEnginePrivate::setOption(QNativeSocketEngine::SocketOption opt return true; } case QNativeSocketEngine::AddressReusable: -#if defined(SO_REUSEPORT) && !defined(Q_OS_SYMBIAN) +#if defined(SO_REUSEPORT) n = SO_REUSEPORT; #else n = SO_REUSEADDR; @@ -425,11 +420,8 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16 } else { // unreachable } -#ifdef Q_OS_SYMBIAN - int connectResult = ::connect(socketDescriptor, sockAddrPtr, sockAddrSize); -#else + int connectResult = qt_safe_connect(socketDescriptor, sockAddrPtr, sockAddrSize); -#endif if (connectResult == -1) { switch (errno) { case EISCONN: @@ -472,9 +464,6 @@ bool QNativeSocketEnginePrivate::nativeConnect(const QHostAddress &addr, quint16 case EBADF: case EFAULT: case ENOTSOCK: -#ifdef Q_OS_SYMBIAN - case EPIPE: -#endif socketState = QAbstractSocket::UnconnectedState; default: break; @@ -573,11 +562,7 @@ bool QNativeSocketEnginePrivate::nativeBind(const QHostAddress &address, quint16 bool QNativeSocketEnginePrivate::nativeListen(int backlog) { -#ifdef Q_OS_SYMBIAN - if (::listen(socketDescriptor, backlog) < 0) { -#else if (qt_safe_listen(socketDescriptor, backlog) < 0) { -#endif switch (errno) { case EADDRINUSE: setError(QAbstractSocket::AddressInUseError, @@ -604,21 +589,12 @@ bool QNativeSocketEnginePrivate::nativeListen(int backlog) int QNativeSocketEnginePrivate::nativeAccept() { -#ifdef Q_OS_SYMBIAN - int acceptedDescriptor = ::accept(socketDescriptor, 0, 0); -#else int acceptedDescriptor = qt_safe_accept(socketDescriptor, 0, 0); -#endif //check if we have valid descriptor at all if(acceptedDescriptor > 0) { // Ensure that the socket is closed on exec*() ::fcntl(acceptedDescriptor, F_SETFD, FD_CLOEXEC); } -#ifdef Q_OS_SYMBIAN - else { - qWarning("QNativeSocketEnginePrivate::nativeAccept() - acceptedDescriptor <= 0"); - } -#endif return acceptedDescriptor; } @@ -793,11 +769,7 @@ qint64 QNativeSocketEnginePrivate::nativeBytesAvailable() const int nbytes = 0; // gives shorter than true amounts on Unix domain sockets. qint64 available = 0; -#ifdef Q_OS_SYMBIAN - if (::ioctl(socketDescriptor, FIONREAD, (char *) &nbytes) >= 0) -#else if (qt_safe_ioctl(socketDescriptor, FIONREAD, (char *) &nbytes) >= 0) -#endif available = (qint64) nbytes; #if defined (QNATIVESOCKETENGINE_DEBUG) @@ -816,15 +788,10 @@ bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const // Peek 0 bytes into the next message. The size of the message may // well be 0, so we can't check recvfrom's return value. ssize_t readBytes; -#ifdef Q_OS_SYMBIAN - char c; - readBytes = ::recvfrom(socketDescriptor, &c, 1, MSG_PEEK, &storage.a, &storageSize); -#else do { char c; readBytes = ::recvfrom(socketDescriptor, &c, 1, MSG_PEEK, &storage.a, &storageSize); } while (readBytes == -1 && errno == EINTR); -#endif // If there's no error, or if our buffer was too small, there must be a // pending datagram. @@ -837,14 +804,6 @@ bool QNativeSocketEnginePrivate::nativeHasPendingDatagrams() const return result; } -#ifdef Q_OS_SYMBIAN -qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const -{ - size_t nbytes = 0; - ::ioctl(socketDescriptor, E32IONREAD, (char *) &nbytes); - return qint64(nbytes-28); -} -#else qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const { QVarLengthArray udpMessagePeekBuffer(8192); @@ -871,7 +830,7 @@ qint64 QNativeSocketEnginePrivate::nativePendingDatagramSize() const return qint64(recvResult); } -#endif + qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxSize, QHostAddress *address, quint16 *port) { @@ -881,17 +840,11 @@ qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxS sz = sizeof(aa); ssize_t recvFromResult = 0; -#ifdef Q_OS_SYMBIAN - char c; - recvFromResult = ::recvfrom(socketDescriptor, maxSize ? data : &c, maxSize ? maxSize : 1, - 0, &aa.a, &sz); -#else do { char c; recvFromResult = ::recvfrom(socketDescriptor, maxSize ? data : &c, maxSize ? maxSize : 1, 0, &aa.a, &sz); } while (recvFromResult == -1 && errno == EINTR); -#endif if (recvFromResult == -1) { setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString); @@ -940,13 +893,8 @@ qint64 QNativeSocketEnginePrivate::nativeSendDatagram(const char *data, qint64 l // ignore the SIGPIPE signal qt_ignore_sigpipe(); -#ifdef Q_OS_SYMBIAN - ssize_t sentBytes = ::sendto(socketDescriptor, data, len, - 0, sockAddrPtr, sockAddrSize); -#else ssize_t sentBytes = qt_safe_sendto(socketDescriptor, data, len, 0, sockAddrPtr, sockAddrSize); -#endif if (sentBytes < 0) { switch (errno) { diff --git a/src/network/socket/qsymbiansocketengine_p.h b/src/network/socket/qsymbiansocketengine_p.h index 3111442..43e5e61 100644 --- a/src/network/socket/qsymbiansocketengine_p.h +++ b/src/network/socket/qsymbiansocketengine_p.h @@ -195,11 +195,9 @@ public: }; void setError(QAbstractSocket::SocketError error, ErrorString errorString) const; -#ifdef Q_OS_SYMBIAN void getPortAndAddress(const TInetAddr& a, quint16 *port, QHostAddress *addr); void setPortAndAddress(TInetAddr& nativeAddr, quint16 port, const QHostAddress &addr); void setError(TInt symbianError); -#endif // FIXME int nativeSelect(int timeout, bool selectForRead) const; -- cgit v0.12 From a97d9d6f2038ddab25d3721817b121dcea61f571 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Wed, 8 Dec 2010 15:57:34 +0100 Subject: Added manual test for socketengine development --- tests/manual/socketengine/main.cpp | 110 +++++++++++++++++++++++++++++ tests/manual/socketengine/socketengine.pro | 13 ++++ 2 files changed, 123 insertions(+) create mode 100644 tests/manual/socketengine/main.cpp create mode 100644 tests/manual/socketengine/socketengine.pro diff --git a/tests/manual/socketengine/main.cpp b/tests/manual/socketengine/main.cpp new file mode 100644 index 0000000..f368573 --- /dev/null +++ b/tests/manual/socketengine/main.cpp @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** 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 test suite 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 +#include +#include +#include +#include +#include +#include "../../auto/network-settings.h" +#include +#include +#include +#include +#include + +const int bufsize = 16*1024; +char buf[bufsize]; + +int main(int argc, char**argv) +{ + // create it + QAbstractSocketEngine *socketEngine = + QAbstractSocketEngine::createSocketEngine(QAbstractSocket::TcpSocket, QNetworkProxy(QNetworkProxy::NoProxy), 0); + if (!socketEngine) { + qDebug() << "could not create engine"; + exit(1); + } + + // initialize it + bool initialized = socketEngine->initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol); + if (!initialized) { + qDebug() << "not able to initialize engine"; + exit(1); + } + + // wait for connected + socketEngine->connectToHost(QHostAddress("74.125.77.99"), 80); // google + bool readyToRead = false; + bool readyToWrite = false; + socketEngine->waitForReadOrWrite(&readyToRead, &readyToWrite, true, true, 10*1000); + if (readyToWrite) { + // write the request + QByteArray request("GET /robots.txt HTTP/1.0\r\n\r\n"); + int ret = socketEngine->write(request.constData(), request.length()); + if (ret == request.length()) { + // read the response in a loop + do { + bool waitReadResult = socketEngine->waitForRead(10*1000); + int available = socketEngine->bytesAvailable(); + if (waitReadResult == true && available == 0) { + // disconnected + exit(0); + } + bzero(buf, bufsize); + ret = socketEngine->read(buf, available); + if (ret > 0) { + printf("%s", buf); + } else { + // some failure when reading + exit(1); + } + } while (1); + } else { + qDebug() << "failed writing"; + } + } else { + qDebug() << "failed connecting"; + } + delete socketEngine; +} + diff --git a/tests/manual/socketengine/socketengine.pro b/tests/manual/socketengine/socketengine.pro new file mode 100644 index 0000000..96d0055 --- /dev/null +++ b/tests/manual/socketengine/socketengine.pro @@ -0,0 +1,13 @@ +load(qttest_p4) +TEMPLATE = app +TARGET = tst_socketengine +DEPENDPATH += . +INCLUDEPATH += . + +QT -= gui +QT += network + +CONFIG += release + +# Input +SOURCES += main.cpp -- cgit v0.12 From 12974d3dad6a8db29479dd1bbf9d280081d60d58 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Wed, 8 Dec 2010 16:47:07 +0000 Subject: Implement sync & async select for symbian socket engine Async select is implemented with an active object rather than using the event dispatcher. Sync select is implemented using User::WaitForRequest to block the thread without requiring an event loop. In both cases, RSocket's KIoctlSelect is used to query the socket state. Reviewed-by: Markus Goetz --- src/network/socket/qsymbiansocketengine.cpp | 253 +++++++++++++++++++++++----- src/network/socket/qsymbiansocketengine_p.h | 36 ++++ 2 files changed, 244 insertions(+), 45 deletions(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index 1d2a11b..ad1164a 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -938,49 +938,65 @@ int QSymbianSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) c int QSymbianSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool checkWrite, bool *selectForRead, bool *selectForWrite) const { + //cancel asynchronous notifier (only one IOCTL allowed at a time) + if (asyncSelect) + asyncSelect->Cancel(); //TODO: implement //as above, but checking both read and write status at the same time - if (!selectTimer.Handle()) - qt_symbian_throwIfError(selectTimer.CreateLocal()); - TRequestStatus timerStat; - selectTimer.HighRes(timerStat, timeout * 1000); - TRequestStatus* readStat = 0; - TRequestStatus* writeStat = 0; - TRequestStatus* array[3]; - array[0] = &timerStat; - int count = 1; - if (checkRead) { - //TODO: get from read AO - //readStat = ? - array[count++] = readStat; - } - if (checkWrite) { - //TODO: get from write AO - //writeStat = ? - array[count++] = writeStat; - } - // TODO: for selecting, we can use getOpt(KSOSelectPoll) to get the select result - // and KIOCtlSelect for the selecting. - User::WaitForNRequest(array, count); - //IMPORTANT - WaitForNRequest only decrements the thread semaphore once, although more than one status may have completed. - if (timerStat.Int() != KRequestPending) { - //timed out - return 0; + TPckgBuf selectFlags; + selectFlags() = KSockSelectExcept; + if (selectForRead) + selectFlags() |= KSockSelectRead; + if (selectForWrite) + selectFlags() |= KSockSelectWrite; + TRequestStatus selectStat; + nativeSocket.Ioctl(KIOctlSelect, selectStat, &selectFlags, KSOLSocket); + + if (timeout < 0) + User::WaitForRequest(selectStat); //negative means no timeout + else { + if (!selectTimer.Handle()) + qt_symbian_throwIfError(selectTimer.CreateLocal()); + TRequestStatus timerStat; + selectTimer.HighRes(timerStat, timeout * 1000); + User::WaitForRequest(timerStat, selectStat); + if (selectStat == KRequestPending) { + nativeSocket.CancelIoctl(); + //CancelIoctl completes the request (most likely with KErrCancel) + //We need to wait for this to keep the thread semaphore balanced (or active scheduler will panic) + User::WaitForRequest(selectStat); + //restart asynchronous notifier (only one IOCTL allowed at a time) + if (asyncSelect) + asyncSelect->IssueRequest(); + return 0; //timeout + } else { + selectTimer.Cancel(); + User::WaitForRequest(timerStat); + } } - selectTimer.Cancel(); - User::WaitForRequest(timerStat); - if(readStat && readStat->Int() != KRequestPending) { + if (selectStat != KErrNone) + return selectStat.Int(); + if (selectFlags() & KSockSelectExcept) { + TInt err; + nativeSocket.GetOpt(KSOSelectLastError, KSOLSocket, err); + //restart asynchronous notifier (only one IOCTL allowed at a time) + if (asyncSelect) + asyncSelect->IssueRequest(); //TODO: in error case should we restart or not? + return err; + } + if (selectFlags() & KSockSelectRead) { Q_ASSERT(checkRead && selectForRead); - //TODO: cancel the AO, but call its RunL anyway? looking for an UnsetActive() *selectForRead = true; } - if(writeStat && writeStat->Int() != KRequestPending) { + if (selectFlags() & KSockSelectWrite) { Q_ASSERT(checkWrite && selectForWrite); - //TODO: cancel the AO, but call its RunL anyway? looking for an UnsetActive() *selectForWrite = true; } + //restart asynchronous notifier (only one IOCTL allowed at a time) + if (asyncSelect) + asyncSelect->IssueRequest(); return 1; } @@ -1150,14 +1166,26 @@ void QSymbianSocketEnginePrivate::setError(QAbstractSocket::SocketError error, E class QReadNotifier : public QSocketNotifier { + friend class QAsyncSelect; public: QReadNotifier(int fd, QSymbianSocketEngine *parent) : QSocketNotifier(fd, QSocketNotifier::Read, parent) { engine = parent; } protected: + bool event(QEvent *); + QSymbianSocketEngine *engine; }; +bool QReadNotifier::event(QEvent *e) +{ + if (e->type() == QEvent::SockAct) { + engine->readNotification(); + return true; + } + return QSocketNotifier::event(e); +} + bool QSymbianSocketEngine::isReadNotificationEnabled() const { Q_D(const QSymbianSocketEngine); @@ -1172,22 +1200,44 @@ void QSymbianSocketEngine::setReadNotificationEnabled(bool enable) if (d->readNotifier) { d->readNotifier->setEnabled(enable); } else if (enable && d->threadData->eventDispatcher) { - d->readNotifier = new QReadNotifier(d->socketDescriptor, this); + QReadNotifier *rn = new QReadNotifier(d->socketDescriptor, this); + d->readNotifier = rn; + if (!d->asyncSelect) + d->asyncSelect = q_check_ptr(new QAsyncSelect(0, d->nativeSocket, this)); + d->asyncSelect->setReadNotifier(rn); d->readNotifier->setEnabled(true); } + // TODO: what do we do if event dispatcher doesn't exist yet? + if (d->asyncSelect) + d->asyncSelect->IssueRequest(); } class QWriteNotifier : public QSocketNotifier { + friend class QAsyncSelect; public: QWriteNotifier(int fd, QSymbianSocketEngine *parent) - : QSocketNotifier(fd, QSocketNotifier::Read, parent) + : QSocketNotifier(fd, QSocketNotifier::Write, parent) { engine = parent; } protected: + bool event(QEvent *); + QSymbianSocketEngine *engine; }; +bool QWriteNotifier::event(QEvent *e) +{ + if (e->type() == QEvent::SockAct) { + if (engine->state() == QAbstractSocket::ConnectingState) + engine->connectionNotification(); + else + engine->writeNotification(); + return true; + } + return QSocketNotifier::event(e); +} + bool QSymbianSocketEngine::isWriteNotificationEnabled() const { Q_D(const QSymbianSocketEngine); @@ -1202,17 +1252,48 @@ void QSymbianSocketEngine::setWriteNotificationEnabled(bool enable) if (d->writeNotifier) { d->writeNotifier->setEnabled(enable); } else if (enable && d->threadData->eventDispatcher) { - d->writeNotifier = new QWriteNotifier(d->socketDescriptor, this); + QWriteNotifier *wn = new QWriteNotifier(d->socketDescriptor, this); + d->readNotifier = wn; + if (!(d->asyncSelect)) + d->asyncSelect = q_check_ptr(new QAsyncSelect(d->threadData->eventDispatcher, d->nativeSocket, this)); + d->asyncSelect->setWriteNotifier(wn); d->writeNotifier->setEnabled(true); } + // TODO: what do we do if event dispatcher doesn't exist yet? + if (d->asyncSelect) + d->asyncSelect->IssueRequest(); +} + +class QExceptionNotifier : public QSocketNotifier +{ + friend class QAsyncSelect; +public: + QExceptionNotifier(int fd, QSymbianSocketEngine *parent) + : QSocketNotifier(fd, QSocketNotifier::Exception, parent) { engine = parent; } + +protected: + bool event(QEvent *); + + QSymbianSocketEngine *engine; +}; + +bool QExceptionNotifier::event(QEvent *e) +{ + if (e->type() == QEvent::SockAct) { + if (engine->state() == QAbstractSocket::ConnectingState) + engine->connectionNotification(); + else + engine->exceptionNotification(); + return true; + } + return QSocketNotifier::event(e); } -// FIXME do we really need this for symbian? bool QSymbianSocketEngine::isExceptionNotificationEnabled() const { -// Q_D(const QSymbianSocketEngine); -// // TODO -// return d->exceptNotifier && d->exceptNotifier->isEnabled(); + Q_D(const QSymbianSocketEngine); + // TODO + return d->exceptNotifier && d->exceptNotifier->isEnabled(); return false; } @@ -1221,12 +1302,18 @@ void QSymbianSocketEngine::setExceptionNotificationEnabled(bool enable) { Q_D(QSymbianSocketEngine); // TODO -// if (d->exceptNotifier) { -// d->exceptNotifier->setEnabled(enable); -// } else if (enable && d->threadData->eventDispatcher) { -// d->exceptNotifier = new QExceptionNotifier(d->socketDescriptor, this); -// d->exceptNotifier->setEnabled(true); -// } + if (d->exceptNotifier) { + d->exceptNotifier->setEnabled(enable); + } else if (enable && d->threadData->eventDispatcher) { + QExceptionNotifier *en = new QExceptionNotifier(d->socketDescriptor, this); + d->exceptNotifier = en; + if (!(d->asyncSelect)) + d->asyncSelect = q_check_ptr(new QAsyncSelect(d->threadData->eventDispatcher, d->nativeSocket, this)); + d->asyncSelect->setExceptionNotifier(en); + d->writeNotifier->setEnabled(true); + } + if (d->asyncSelect) + d->asyncSelect->IssueRequest(); } bool QSymbianSocketEngine::waitForRead(int msecs, bool *timedOut) @@ -1302,5 +1389,81 @@ qint64 QSymbianSocketEngine::bytesToWrite() const return 0; } +QAsyncSelect::QAsyncSelect(QAbstractEventDispatcher *dispatcher, RSocket& sock, QSymbianSocketEngine *parent) + : CActive(CActive::EPriorityStandard), + m_inSocketEvent(false), + m_deleteLater(false), + m_socket(sock), + m_selectFlags(0), + engine(parent) +{ + CActiveScheduler::Add(this); +} + +QAsyncSelect::~QAsyncSelect() +{ + Cancel(); +} + +void QAsyncSelect::DoCancel() +{ + m_socket.CancelIoctl(); +} + +void QAsyncSelect::RunL() +{ + //TODO: block when event loop demands it + //if (maybeQueueForLater()) + // return; + + m_inSocketEvent = true; + //TODO: KSockSelectReadContinuation does what? + if (m_selectBuf() & KSockSelectRead) { + QEvent e(QEvent::SockAct); + iReadN->event(&e); + } + if (m_selectBuf() & KSockSelectWrite) { + QEvent e(QEvent::SockAct); + iWriteN->event(&e); + } + if ((m_selectBuf() && KSockSelectExcept) || iStatus != KErrNone) { + QEvent e(QEvent::SockAct); + iExcN->event(&e); + } + m_inSocketEvent = false; + // select again (unless disabled by one of the callbacks) + IssueRequest(); +} + +void QAsyncSelect::deleteLater() +{ + if (m_inSocketEvent) { + m_deleteLater = true; + } else { + delete this; + } +} + +void QAsyncSelect::IssueRequest() +{ + if (m_inSocketEvent) + return; //prevent thrashing during a callback - socket engine enables/disables multiple notifiers + TUint selectFlags = 0; + if (iReadN && iReadN->isEnabled()) + selectFlags |= KSockSelectRead; + if (iWriteN && iWriteN->isEnabled()) + selectFlags |= KSockSelectWrite; + if (iExcN && iExcN->isEnabled()) + selectFlags |= KSockSelectExcept; + if (selectFlags != m_selectFlags) { + Cancel(); + m_selectFlags = selectFlags; + } + if (m_selectFlags && !IsActive()) { + m_selectBuf() = m_selectFlags; + m_socket.Ioctl(KIOctlSelect, iStatus, &m_selectBuf, KSOLSocket); + SetActive(); + } +} QT_END_NAMESPACE diff --git a/src/network/socket/qsymbiansocketengine_p.h b/src/network/socket/qsymbiansocketengine_p.h index 43e5e61..ebd8092 100644 --- a/src/network/socket/qsymbiansocketengine_p.h +++ b/src/network/socket/qsymbiansocketengine_p.h @@ -146,6 +146,41 @@ private: class QSocketNotifier; +class QReadNotifier; +class QWriteNotifier; +class QExceptionNotifier; +class QAsyncSelect : public CActive +{ +public: + QAsyncSelect(QAbstractEventDispatcher *dispatcher, RSocket& sock, QSymbianSocketEngine *parent); + ~QAsyncSelect(); + + void deleteLater(); + void IssueRequest(); + + void refresh(); + + void setReadNotifier(QReadNotifier *rn) { iReadN = rn; } + void setWriteNotifier(QWriteNotifier *wn) { iWriteN = wn; } + void setExceptionNotifier(QExceptionNotifier *en) { iExcN = en; } + +protected: + void DoCancel(); + void RunL(); + +private: + QReadNotifier* iReadN; + QWriteNotifier* iWriteN; + QExceptionNotifier* iExcN; + bool m_inSocketEvent; // TODO ? + bool m_deleteLater; // TODO ? + RSocket &m_socket; + + TUint m_selectFlags; + TPckgBuf m_selectBuf; //in & out IPC buffer + QSymbianSocketEngine *engine; +}; + class QSymbianSocketEnginePrivate : public QAbstractSocketEnginePrivate { Q_DECLARE_PUBLIC(QSymbianSocketEngine) @@ -162,6 +197,7 @@ public: mutable RTimer selectTimer; QSocketNotifier *readNotifier, *writeNotifier, *exceptNotifier; + QAsyncSelect* asyncSelect; // FIXME this is duplicated from qnativesocketengine_p.h enum ErrorString { -- cgit v0.12 From 82ab30acff0322f51f732c520dd1e5d7b40482a6 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Wed, 8 Dec 2010 19:25:29 +0000 Subject: Whitespace fixes Reviewed-by: Trust Me --- src/network/kernel/qhostinfo_symbian.cpp | 2 +- src/network/socket/qsymbiansocketengine.cpp | 8 ++++---- src/network/socket/qsymbiansocketengine_p.h | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/network/kernel/qhostinfo_symbian.cpp b/src/network/kernel/qhostinfo_symbian.cpp index ffa0b46..287021f 100644 --- a/src/network/kernel/qhostinfo_symbian.cpp +++ b/src/network/kernel/qhostinfo_symbian.cpp @@ -88,7 +88,7 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) results.setErrorString(QString::fromLocal8Bit(gai_strerror(result))); } */ - + return results; } diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index ad1164a..2af2029 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -119,7 +119,7 @@ void QSymbianSocketEnginePrivate::getPortAndAddress(const TInetAddr& a, quint16 TPckgBuf query; query().iSrcAddr = a; TInt err = nativeSocket.GetOpt(KSoInetIfQueryBySrcAddr, KSolInetIfQuery, query); - if(!err) + if (!err) addr->setScopeId(qt_TDesC2QString(query().iName)); else addr->setScopeId(QString::number(a.Scope())); @@ -181,7 +181,7 @@ void QSymbianSocketEnginePrivate::setPortAndAddress(TInetAddr& nativeAddr, quint TPckgBuf query; query().iName = qt_QString2TPtrC(addr.scopeId()); TInt err = nativeSocket.GetOpt(KSoInetIfQueryByName, KSolInetIfQuery, query); - if(!err) + if (!err) nativeAddr.SetScope(query().iIndex); else nativeAddr.SetScope(0); @@ -638,7 +638,7 @@ int QSymbianSocketEngine::accept() TRequestStatus status; d->nativeSocket.Accept(blankSocket, status); User::WaitForRequest(status); - if(status.Int()) { + if (status.Int()) { qWarning("QSymbianSocketEnginePrivate::nativeAccept() - error %d", status.Int()); return 0; } @@ -655,7 +655,7 @@ qint64 QSymbianSocketEngine::bytesAvailable() const // FIXME is this the right thing also for UDP? // What is expected for UDP, the length for the next packet I guess? TInt err = d->nativeSocket.GetOpt(KSOReadBytesPending, KSOLSocket, nbytes); - if(err) + if (err) return 0; available = (qint64) nbytes; diff --git a/src/network/socket/qsymbiansocketengine_p.h b/src/network/socket/qsymbiansocketengine_p.h index ebd8092..2d5bcd8 100644 --- a/src/network/socket/qsymbiansocketengine_p.h +++ b/src/network/socket/qsymbiansocketengine_p.h @@ -124,8 +124,8 @@ public: bool waitForRead(int msecs = 30000, bool *timedOut = 0); bool waitForWrite(int msecs = 30000, bool *timedOut = 0); bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite, - bool checkRead, bool checkWrite, - int msecs = 30000, bool *timedOut = 0); + bool checkRead, bool checkWrite, + int msecs = 30000, bool *timedOut = 0); bool isReadNotificationEnabled() const; void setReadNotificationEnabled(bool enable); -- cgit v0.12 From 92705ba069945bdd9a65b627d89119a893c0cf1e Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Wed, 8 Dec 2010 19:33:18 +0000 Subject: Fix handling of select ioctl results The select ioctl report everything not just the flags we asked for. So mask off the results to only look at the requested flags. Reviewed-by: Markus Goetz --- src/network/socket/qsymbiansocketengine.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index 2af2029..b1d8bc0 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -986,12 +986,12 @@ int QSymbianSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool asyncSelect->IssueRequest(); //TODO: in error case should we restart or not? return err; } - if (selectFlags() & KSockSelectRead) { - Q_ASSERT(checkRead && selectForRead); + if (checkRead && (selectFlags() & KSockSelectRead)) { + Q_ASSERT(selectForRead); *selectForRead = true; } - if (selectFlags() & KSockSelectWrite) { - Q_ASSERT(checkWrite && selectForWrite); + if (checkWrite && (selectFlags() & KSockSelectWrite)) { + Q_ASSERT(selectForWrite); *selectForWrite = true; } //restart asynchronous notifier (only one IOCTL allowed at a time) @@ -1417,6 +1417,7 @@ void QAsyncSelect::RunL() // return; m_inSocketEvent = true; + m_selectBuf() &= m_selectFlags; //the select ioctl reports everything, so mask to only what we requested //TODO: KSockSelectReadContinuation does what? if (m_selectBuf() & KSockSelectRead) { QEvent e(QEvent::SockAct); -- cgit v0.12 From d7654f94c61d562c8673de577c1cf934f3026614 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Wed, 8 Dec 2010 20:14:31 +0100 Subject: QSymbianSocketEngine: Unify a call --- src/network/socket/qsymbiansocketengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index b1d8bc0..e7bd425 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -198,7 +198,7 @@ void QSymbianSocketEnginePrivate::setPortAndAddress(TInetAddr& nativeAddr, quint QSymbianSocketEnginePrivate::QSymbianSocketEnginePrivate() : socketDescriptor(-1), - socketServer(qt_symbianGetSocketServer()), + socketServer(QSymbianSocketManager::instance().getSocketServer()), connection(QSymbianSocketManager::instance().defaultConnection()), readNotifier(0), writeNotifier(0), -- cgit v0.12 From afc7d05995c8f56d0ab9c35f9ca826e0bd0aaea4 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Wed, 8 Dec 2010 20:16:27 +0100 Subject: Socket engines: Improve manual test program Reviewed-by: Shane Kearns --- tests/manual/socketengine/main.cpp | 36 ++++++++++++++++++++++++++++++ tests/manual/socketengine/socketengine.pro | 2 ++ 2 files changed, 38 insertions(+) diff --git a/tests/manual/socketengine/main.cpp b/tests/manual/socketengine/main.cpp index f368573..e475942 100644 --- a/tests/manual/socketengine/main.cpp +++ b/tests/manual/socketengine/main.cpp @@ -51,12 +51,48 @@ #include #include #include +#include +#include +#include +#include const int bufsize = 16*1024; char buf[bufsize]; int main(int argc, char**argv) { + QCoreApplication app(argc, argv); + +#ifdef Q_OS_SYMBIAN + QNetworkConfigurationManager configurationManager; + QNetworkConfiguration configuration = configurationManager.defaultConfiguration(); + if (!configuration.isValid()) { + qDebug() << "Got an invalid session configuration"; + exit(1); + } + + qDebug() << "Opening session..."; + QNetworkSession *session = new QNetworkSession(configuration); + + // Does not work: +// session->open(); +// session->waitForOpened(); + + // works: + QEventLoop loop; + QObject::connect(session, SIGNAL(opened()), &loop, SLOT(quit()), Qt::QueuedConnection); + QMetaObject::invokeMethod(session, "open", Qt::QueuedConnection); + loop.exec(); + + + if (session->isOpen()) { + qDebug() << "session opened"; + } else { + qDebug() << "session could not be opened -" << session->errorString(); + exit(1); + } +#endif + // create it QAbstractSocketEngine *socketEngine = QAbstractSocketEngine::createSocketEngine(QAbstractSocket::TcpSocket, QNetworkProxy(QNetworkProxy::NoProxy), 0); diff --git a/tests/manual/socketengine/socketengine.pro b/tests/manual/socketengine/socketengine.pro index 96d0055..76a40be 100644 --- a/tests/manual/socketengine/socketengine.pro +++ b/tests/manual/socketengine/socketengine.pro @@ -9,5 +9,7 @@ QT += network CONFIG += release +symbian: TARGET.CAPABILITY = NetworkServices + # Input SOURCES += main.cpp -- cgit v0.12 From 92f11bd666e8a63d9fc8c5588d843721c5bf68b5 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Wed, 8 Dec 2010 20:27:03 +0100 Subject: QSymbianSocketEngine: Fix wrong debug message --- src/network/socket/qsymbiansocketengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index e7bd425..5cee340 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -540,7 +540,7 @@ bool QSymbianSocketEngine::connectToHost(const QHostAddress &addr, quint16 port) if (d->socketState != QAbstractSocket::ConnectedState) { #if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QSymbianSocketEnginePrivate::nativeConnect(%s, %i) == false (%s)", + qDebug("QSymbianSocketEngine::connectToHost(%s, %i) == false (%s)", addr.toString().toLatin1().constData(), port, d->socketState == QAbstractSocket::ConnectingState ? "Connection in progress" : d->socketErrorString.toLatin1().constData()); -- cgit v0.12 From b9080b96b05988776daec35f7e2af9ad346abb0a Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Thu, 9 Dec 2010 10:05:03 +0000 Subject: Fix bug in select When waitForRead was called, it was selecting for read and write, because we were checking the pointers instead of the bools. Reviewed-by: Markus Goetz --- src/network/socket/qsymbiansocketengine.cpp | 10 +++++++--- tests/manual/socketengine/main.cpp | 8 +++++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index 5cee340..1490bdd 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -148,7 +148,11 @@ bool QSymbianSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType so TUint family = (socketProtocol == QAbstractSocket::IPv6Protocol) ? KAfInet6 : KAfInet; TUint type = (socketType == QAbstractSocket::UdpSocket) ? KSockDatagram : KSockStream; TUint protocol = (socketType == QAbstractSocket::UdpSocket) ? KProtocolInetUdp : KProtocolInetTcp; - TInt err = nativeSocket.Open(socketServer, family, type, protocol, *connection); + TInt err; + if (connection) + err = nativeSocket.Open(socketServer, family, type, protocol, *connection); + else + err = nativeSocket.Open(socketServer, family, type, protocol); //TODO: FIXME - deprecated API, make sure we always have a connection instead if (err != KErrNone) { switch (err) { @@ -946,9 +950,9 @@ int QSymbianSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool TPckgBuf selectFlags; selectFlags() = KSockSelectExcept; - if (selectForRead) + if (checkRead) selectFlags() |= KSockSelectRead; - if (selectForWrite) + if (checkWrite) selectFlags() |= KSockSelectWrite; TRequestStatus selectStat; nativeSocket.Ioctl(KIOctlSelect, selectStat, &selectFlags, KSOLSocket); diff --git a/tests/manual/socketengine/main.cpp b/tests/manual/socketengine/main.cpp index e475942..2f017a0 100644 --- a/tests/manual/socketengine/main.cpp +++ b/tests/manual/socketengine/main.cpp @@ -109,10 +109,12 @@ int main(int argc, char**argv) } // wait for connected - socketEngine->connectToHost(QHostAddress("74.125.77.99"), 80); // google + int r = socketEngine->connectToHost(QHostAddress("74.125.77.99"), 80); // google bool readyToRead = false; bool readyToWrite = false; socketEngine->waitForReadOrWrite(&readyToRead, &readyToWrite, true, true, 10*1000); + if (r <= 0) //timeout or error + exit(1); if (readyToWrite) { // write the request QByteArray request("GET /robots.txt HTTP/1.0\r\n\r\n"); @@ -129,7 +131,11 @@ int main(int argc, char**argv) bzero(buf, bufsize); ret = socketEngine->read(buf, available); if (ret > 0) { +#ifdef Q_OS_SYMBIAN + qDebug() << buf; //printf goes only to screen, this goes to remote debug channel +#else printf("%s", buf); +#endif } else { // some failure when reading exit(1); -- cgit v0.12 From af62350d83b27421820536b3a19be36a32384f15 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Thu, 9 Dec 2010 14:53:34 +0100 Subject: Move tst_qnativesocketengine to tst_platformsocketengine --- tests/auto/platformsocketengine/.gitignore | 1 + .../platformsocketengine/platformsocketengine.pri | 19 + .../platformsocketengine/platformsocketengine.pro | 13 + .../tst_platformsocketengine.cpp | 705 +++++++++++++++++++++ tests/auto/qnativesocketengine/.gitignore | 1 - .../qnativesocketengine/qnativesocketengine.pro | 13 - tests/auto/qnativesocketengine/qsocketengine.pri | 19 - .../tst_qnativesocketengine.cpp | 705 --------------------- 8 files changed, 738 insertions(+), 738 deletions(-) create mode 100644 tests/auto/platformsocketengine/.gitignore create mode 100644 tests/auto/platformsocketengine/platformsocketengine.pri create mode 100644 tests/auto/platformsocketengine/platformsocketengine.pro create mode 100644 tests/auto/platformsocketengine/tst_platformsocketengine.cpp delete mode 100644 tests/auto/qnativesocketengine/.gitignore delete mode 100644 tests/auto/qnativesocketengine/qnativesocketengine.pro delete mode 100644 tests/auto/qnativesocketengine/qsocketengine.pri delete mode 100644 tests/auto/qnativesocketengine/tst_qnativesocketengine.cpp diff --git a/tests/auto/platformsocketengine/.gitignore b/tests/auto/platformsocketengine/.gitignore new file mode 100644 index 0000000..4700e5e --- /dev/null +++ b/tests/auto/platformsocketengine/.gitignore @@ -0,0 +1 @@ +tst_qnativesocketengine diff --git a/tests/auto/platformsocketengine/platformsocketengine.pri b/tests/auto/platformsocketengine/platformsocketengine.pri new file mode 100644 index 0000000..15f31fd --- /dev/null +++ b/tests/auto/platformsocketengine/platformsocketengine.pri @@ -0,0 +1,19 @@ +QT += network + +QNETWORK_SRC = $$QT_SOURCE_TREE/src/network + +INCLUDEPATH += $$QNETWORK_SRC + +win32 { + wince*: { + LIBS += -lws2 + } else { + LIBS += -lws2_32 + } +} + +unix:contains(QT_CONFIG, reduce_exports) { + SOURCES += $$QNETWORK_SRC/socket/qnativesocketengine_unix.cpp + SOURCES += $$QNETWORK_SRC/socket/qnativesocketengine.cpp + SOURCES += $$QNETWORK_SRC/socket/qabstractsocketengine.cpp +} diff --git a/tests/auto/platformsocketengine/platformsocketengine.pro b/tests/auto/platformsocketengine/platformsocketengine.pro new file mode 100644 index 0000000..0275d37 --- /dev/null +++ b/tests/auto/platformsocketengine/platformsocketengine.pro @@ -0,0 +1,13 @@ +load(qttest_p4) +SOURCES += tst_qnativesocketengine.cpp + +include(../qnativesocketengine/qsocketengine.pri) + +requires(contains(QT_CONFIG,private_tests)) + +MOC_DIR=tmp + +QT = core network + +symbian: TARGET.CAPABILITY = NetworkServices + diff --git a/tests/auto/platformsocketengine/tst_platformsocketengine.cpp b/tests/auto/platformsocketengine/tst_platformsocketengine.cpp new file mode 100644 index 0000000..2b0b632 --- /dev/null +++ b/tests/auto/platformsocketengine/tst_platformsocketengine.cpp @@ -0,0 +1,705 @@ +/**************************************************************************** +** +** 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 test suite 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 + +#ifdef Q_OS_WIN +#include +#endif + +#include + + +#include +#include + +#include +#include + +#ifdef Q_OS_UNIX +#include +#include +#include +#endif + +#include + + +#include + +#include "../network-settings.h" + +//TESTED_FILES=network/qnativesocketengine.cpp network/qnativesocketengine_p.h network/qnativesocketengine_unix.cpp + +class tst_QNativeSocketEngine : public QObject +{ + Q_OBJECT + +public: + tst_QNativeSocketEngine(); + virtual ~tst_QNativeSocketEngine(); + + +public slots: + void init(); + void cleanup(); +private slots: + void construction(); + void simpleConnectToIMAP(); + void udpLoopbackTest(); + void udpIPv6LoopbackTest(); + void broadcastTest(); + void serverTest(); + void udpLoopbackPerformance(); + void tcpLoopbackPerformance(); + void readWriteBufferSize(); + void tooManySockets(); + void bind(); + void networkError(); + void setSocketDescriptor(); + void invalidSend(); + void receiveUrgentData(); +}; + +tst_QNativeSocketEngine::tst_QNativeSocketEngine() +{ + Q_SET_DEFAULT_IAP +} + +tst_QNativeSocketEngine::~tst_QNativeSocketEngine() +{ +} + +void tst_QNativeSocketEngine::init() +{ +} + +void tst_QNativeSocketEngine::cleanup() +{ +} + +//--------------------------------------------------------------------------- +void tst_QNativeSocketEngine::construction() +{ + QNativeSocketEngine socketDevice; + + QVERIFY(!socketDevice.isValid()); + + // Initialize device + QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); + QVERIFY(socketDevice.isValid()); + QVERIFY(socketDevice.protocol() == QAbstractSocket::IPv4Protocol); + QVERIFY(socketDevice.socketType() == QAbstractSocket::TcpSocket); + QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState); + QVERIFY(socketDevice.socketDescriptor() != -1); + QVERIFY(socketDevice.localAddress() == QHostAddress()); + QVERIFY(socketDevice.localPort() == 0); + QVERIFY(socketDevice.peerAddress() == QHostAddress()); + QVERIFY(socketDevice.peerPort() == 0); + QVERIFY(socketDevice.error() == QAbstractSocket::UnknownSocketError); + + QTest::ignoreMessage(QtWarningMsg, "QNativeSocketEngine::bytesAvailable() was called in QAbstractSocket::UnconnectedState"); + QVERIFY(socketDevice.bytesAvailable() == 0); + + QTest::ignoreMessage(QtWarningMsg, "QNativeSocketEngine::hasPendingDatagrams() was called in QAbstractSocket::UnconnectedState"); + QVERIFY(!socketDevice.hasPendingDatagrams()); +} + +//--------------------------------------------------------------------------- +void tst_QNativeSocketEngine::simpleConnectToIMAP() +{ + QNativeSocketEngine socketDevice; + + // Initialize device + QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); + QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState); + + const bool isConnected = socketDevice.connectToHost(QtNetworkSettings::serverIP(), 143); + if (!isConnected) { + QVERIFY(socketDevice.state() == QAbstractSocket::ConnectingState); + QVERIFY(socketDevice.waitForWrite()); + QVERIFY(socketDevice.state() == QAbstractSocket::ConnectedState); + } + QVERIFY(socketDevice.state() == QAbstractSocket::ConnectedState); + QVERIFY(socketDevice.peerAddress() == QtNetworkSettings::serverIP()); + + // Wait for the greeting + QVERIFY(socketDevice.waitForRead()); + + // Read the greeting + qint64 available = socketDevice.bytesAvailable(); + QVERIFY(available > 0); + QByteArray array; + array.resize(available); + QVERIFY(socketDevice.read(array.data(), array.size()) == available); + + // Check that the greeting is what we expect it to be + QCOMPARE(array.constData(), QtNetworkSettings::expectedReplyIMAP().constData()); + + // Write a logout message + QByteArray array2 = "ZZZ LOGOUT\r\n"; + QVERIFY(socketDevice.write(array2.data(), + array2.size()) == array2.size()); + + // Wait for the response + QVERIFY(socketDevice.waitForRead()); + + available = socketDevice.bytesAvailable(); + QVERIFY(available > 0); + array.resize(available); + QVERIFY(socketDevice.read(array.data(), array.size()) == available); + + // Check that the greeting is what we expect it to be + QCOMPARE(array.constData(), + "* BYE LOGOUT received\r\n" + "ZZZ OK Completed\r\n"); + + // Wait for the response + QVERIFY(socketDevice.waitForRead()); + char c; + QVERIFY(socketDevice.read(&c, sizeof(c)) == -1); + QVERIFY(socketDevice.error() == QAbstractSocket::RemoteHostClosedError); + QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState); +} + +//--------------------------------------------------------------------------- +void tst_QNativeSocketEngine::udpLoopbackTest() +{ +#ifdef SYMBIAN_WINSOCK_CONNECTIVITY + QSKIP("Not working on Emulator without WinPCAP", SkipAll); +#endif + QNativeSocketEngine udpSocket; + + // Initialize device #1 + QVERIFY(udpSocket.initialize(QAbstractSocket::UdpSocket)); + QVERIFY(udpSocket.isValid()); + QVERIFY(udpSocket.socketDescriptor() != -1); + QVERIFY(udpSocket.protocol() == QAbstractSocket::IPv4Protocol); + QVERIFY(udpSocket.socketType() == QAbstractSocket::UdpSocket); + QVERIFY(udpSocket.state() == QAbstractSocket::UnconnectedState); + + // Bind #1 to localhost + QVERIFY(udpSocket.bind(QHostAddress("127.0.0.1"), 0)); + QVERIFY(udpSocket.state() == QAbstractSocket::BoundState); + quint16 port = udpSocket.localPort(); + QVERIFY(port != 0); + + // Initialize device #2 + QNativeSocketEngine udpSocket2; + QVERIFY(udpSocket2.initialize(QAbstractSocket::UdpSocket)); + + // Connect device #2 to #1 + QVERIFY(udpSocket2.connectToHost(QHostAddress("127.0.0.1"), port)); + QVERIFY(udpSocket2.state() == QAbstractSocket::ConnectedState); + + // Write a message to #1 + QByteArray message1 = "hei der"; + QVERIFY(udpSocket2.write(message1.data(), + message1.size()) == message1.size()); + + // Read the message from #2 + QVERIFY(udpSocket.waitForRead()); + QVERIFY(udpSocket.hasPendingDatagrams()); + qint64 available = udpSocket.pendingDatagramSize(); + QVERIFY(available > 0); + QByteArray answer; + answer.resize(available); + QHostAddress senderAddress; + quint16 senderPort = 0; + QVERIFY(udpSocket.readDatagram(answer.data(), answer.size(), + &senderAddress, + &senderPort) == message1.size()); + QVERIFY(senderAddress == QHostAddress("127.0.0.1")); + QVERIFY(senderPort != 0); +} + +//--------------------------------------------------------------------------- +void tst_QNativeSocketEngine::udpIPv6LoopbackTest() +{ +#if defined(Q_OS_SYMBIAN) + QSKIP("Symbian: IPv6 is not yet supported", SkipAll); +#endif + QNativeSocketEngine udpSocket; + + // Initialize device #1 + bool init = udpSocket.initialize(QAbstractSocket::UdpSocket, QAbstractSocket::IPv6Protocol); + + if (!init) { + QVERIFY(udpSocket.error() == QAbstractSocket::UnsupportedSocketOperationError); + } else { + QVERIFY(udpSocket.protocol() == QAbstractSocket::IPv6Protocol); + + // Bind #1 to localhost + QVERIFY(udpSocket.bind(QHostAddress("::1"), 0)); + QVERIFY(udpSocket.state() == QAbstractSocket::BoundState); + quint16 port = udpSocket.localPort(); + QVERIFY(port != 0); + + // Initialize device #2 + QNativeSocketEngine udpSocket2; + QVERIFY(udpSocket2.initialize(QAbstractSocket::UdpSocket, QAbstractSocket::IPv6Protocol)); + + // Connect device #2 to #1 + QVERIFY(udpSocket2.connectToHost(QHostAddress("::1"), port)); + QVERIFY(udpSocket2.state() == QAbstractSocket::ConnectedState); + + // Write a message to #1 + QByteArray message1 = "hei der"; + QVERIFY(udpSocket2.write(message1.data(), + message1.size()) == message1.size()); + + // Read the message from #2 + QVERIFY(udpSocket.waitForRead()); + QVERIFY(udpSocket.hasPendingDatagrams()); + qint64 available = udpSocket.pendingDatagramSize(); + QVERIFY(available > 0); + QByteArray answer; + answer.resize(available); + QHostAddress senderAddress; + quint16 senderPort = 0; + QVERIFY(udpSocket.readDatagram(answer.data(), answer.size(), + &senderAddress, + &senderPort) == message1.size()); + QVERIFY(senderAddress == QHostAddress("::1")); + QVERIFY(senderPort != 0); + } +} + +//--------------------------------------------------------------------------- +void tst_QNativeSocketEngine::broadcastTest() +{ +#ifdef Q_OS_AIX + QSKIP("Broadcast does not work on darko", SkipAll); +#endif + QNativeSocketEngine broadcastSocket; + + // Initialize a regular Udp socket + QVERIFY(broadcastSocket.initialize(QAbstractSocket::UdpSocket)); + + // Bind to any port on all interfaces + QVERIFY(broadcastSocket.bind(QHostAddress::Any, 0)); + QVERIFY(broadcastSocket.state() == QAbstractSocket::BoundState); + quint16 port = broadcastSocket.localPort(); + QVERIFY(port > 0); + + // Broadcast an inappropriate troll message + QByteArray trollMessage + = "MOOT wtf is a MOOT? talk english not your sutpiD ENGLISH."; + QVERIFY(broadcastSocket.writeDatagram(trollMessage.data(), + trollMessage.size(), + QHostAddress::Broadcast, + port) == trollMessage.size()); + + // Wait until we receive it ourselves +#if defined(Q_OS_FREEBSD) + QEXPECT_FAIL("", "Broadcasting to 255.255.255.255 does not work on FreeBSD", Abort); +#endif + QVERIFY(broadcastSocket.waitForRead()); + QVERIFY(broadcastSocket.hasPendingDatagrams()); + + qlonglong available = broadcastSocket.pendingDatagramSize(); + QByteArray response; + response.resize(available); + QVERIFY(broadcastSocket.readDatagram(response.data(), response.size()) + == response.size()); + QCOMPARE(response, trollMessage); + +} + +//--------------------------------------------------------------------------- +void tst_QNativeSocketEngine::serverTest() +{ + QNativeSocketEngine server; + + // Initialize a Tcp socket + QVERIFY(server.initialize(QAbstractSocket::TcpSocket)); + + // Bind to any port on all interfaces + QVERIFY(server.bind(QHostAddress("0.0.0.0"), 0)); + QVERIFY(server.state() == QAbstractSocket::BoundState); + quint16 port = server.localPort(); + + // Listen for incoming connections + QVERIFY(server.listen()); + QVERIFY(server.state() == QAbstractSocket::ListeningState); + + // Initialize a Tcp socket + QNativeSocketEngine client; + QVERIFY(client.initialize(QAbstractSocket::TcpSocket)); + if (!client.connectToHost(QHostAddress("127.0.0.1"), port)) { + QVERIFY(client.state() == QAbstractSocket::ConnectingState); + QVERIFY(client.waitForWrite()); + QVERIFY(client.state() == QAbstractSocket::ConnectedState); + } + + // The server accepts the connection + int socketDescriptor = server.accept(); + QVERIFY(socketDescriptor > 0); + + // A socket device is initialized on the server side, passing the + // socket descriptor from accept(). It's pre-connected. + QNativeSocketEngine serverSocket; + QVERIFY(serverSocket.initialize(socketDescriptor)); + QVERIFY(serverSocket.state() == QAbstractSocket::ConnectedState); + + // The server socket sends a greeting to the clietn + QByteArray greeting = "Greetings!"; + QVERIFY(serverSocket.write(greeting.data(), + greeting.size()) == greeting.size()); + + // The client waits for the greeting to arrive + QVERIFY(client.waitForRead()); + qint64 available = client.bytesAvailable(); + QVERIFY(available > 0); + + // The client reads the greeting and checks that it's correct + QByteArray response; + response.resize(available); + QVERIFY(client.read(response.data(), + response.size()) == response.size()); + QCOMPARE(response, greeting); +} + +//--------------------------------------------------------------------------- +void tst_QNativeSocketEngine::udpLoopbackPerformance() +{ +#ifdef SYMBIAN_WINSOCK_CONNECTIVITY + QSKIP("Not working on Emulator without WinPCAP", SkipAll); +#endif + QNativeSocketEngine udpSocket; + + // Initialize device #1 + QVERIFY(udpSocket.initialize(QAbstractSocket::UdpSocket)); + QVERIFY(udpSocket.isValid()); + QVERIFY(udpSocket.socketDescriptor() != -1); + QVERIFY(udpSocket.protocol() == QAbstractSocket::IPv4Protocol); + QVERIFY(udpSocket.socketType() == QAbstractSocket::UdpSocket); + QVERIFY(udpSocket.state() == QAbstractSocket::UnconnectedState); + + // Bind #1 to localhost + QVERIFY(udpSocket.bind(QHostAddress("127.0.0.1"), 0)); + QVERIFY(udpSocket.state() == QAbstractSocket::BoundState); + quint16 port = udpSocket.localPort(); + QVERIFY(port != 0); + + // Initialize device #2 + QNativeSocketEngine udpSocket2; + QVERIFY(udpSocket2.initialize(QAbstractSocket::UdpSocket)); + + // Connect device #2 to #1 + QVERIFY(udpSocket2.connectToHost(QHostAddress("127.0.0.1"), port)); + QVERIFY(udpSocket2.state() == QAbstractSocket::ConnectedState); + + const int messageSize = 8192; + QByteArray message1(messageSize, '@'); + QByteArray answer(messageSize, '@'); + + QHostAddress localhost = QHostAddress::LocalHost; + + qlonglong readBytes = 0; + QTime timer; + timer.start(); + while (timer.elapsed() < 5000) { + udpSocket2.write(message1.data(), message1.size()); + udpSocket.waitForRead(); + while (udpSocket.hasPendingDatagrams()) { + readBytes += (qlonglong) udpSocket.readDatagram(answer.data(), + answer.size()); + } + } + + qDebug("\t\t%.1fMB/%.1fs: %.1fMB/s", + readBytes / (1024.0 * 1024.0), + timer.elapsed() / 1024.0, + (readBytes / (timer.elapsed() / 1000.0)) / (1024 * 1024)); +} + +//--------------------------------------------------------------------------- +void tst_QNativeSocketEngine::tcpLoopbackPerformance() +{ + QNativeSocketEngine server; + + // Initialize a Tcp socket + QVERIFY(server.initialize(QAbstractSocket::TcpSocket)); + + // Bind to any port on all interfaces + QVERIFY(server.bind(QHostAddress("0.0.0.0"), 0)); + QVERIFY(server.state() == QAbstractSocket::BoundState); + quint16 port = server.localPort(); + + // Listen for incoming connections + QVERIFY(server.listen()); + QVERIFY(server.state() == QAbstractSocket::ListeningState); + + // Initialize a Tcp socket + QNativeSocketEngine client; + QVERIFY(client.initialize(QAbstractSocket::TcpSocket)); + + // Connect to our server + if (!client.connectToHost(QHostAddress("127.0.0.1"), port)) { + QVERIFY(client.state() == QAbstractSocket::ConnectingState); + QVERIFY(client.waitForWrite()); + QVERIFY(client.state() == QAbstractSocket::ConnectedState); + } + + // The server accepts the connectio + int socketDescriptor = server.accept(); + QVERIFY(socketDescriptor > 0); + + // A socket device is initialized on the server side, passing the + // socket descriptor from accept(). It's pre-connected. + QNativeSocketEngine serverSocket; + QVERIFY(serverSocket.initialize(socketDescriptor)); + QVERIFY(serverSocket.state() == QAbstractSocket::ConnectedState); + + const int messageSize = 1024 * 256; + QByteArray message1(messageSize, '@'); + QByteArray answer(messageSize, '@'); + + QTime timer; + timer.start(); + qlonglong readBytes = 0; + while (timer.elapsed() < 5000) { + qlonglong written = serverSocket.write(message1.data(), message1.size()); + while (written > 0) { + client.waitForRead(); + if (client.bytesAvailable() > 0) { + qlonglong readNow = client.read(answer.data(), answer.size()); + written -= readNow; + readBytes += readNow; + } + } + } + + qDebug("\t\t%.1fMB/%.1fs: %.1fMB/s", + readBytes / (1024.0 * 1024.0), + timer.elapsed() / 1024.0, + (readBytes / (timer.elapsed() / 1000.0)) / (1024 * 1024)); +} + +//--------------------------------------------------------------------------- +void tst_QNativeSocketEngine::readWriteBufferSize() +{ + QNativeSocketEngine device; + + QVERIFY(device.initialize(QAbstractSocket::TcpSocket)); + + qint64 bufferSize = device.receiveBufferSize(); + QVERIFY(bufferSize != -1); + device.setReceiveBufferSize(bufferSize + 1); +#if defined(Q_OS_WINCE) + QEXPECT_FAIL(0, "Not supported by default on WinCE", Continue); +#endif + QVERIFY(device.receiveBufferSize() > bufferSize); + + bufferSize = device.sendBufferSize(); + QVERIFY(bufferSize != -1); + device.setSendBufferSize(bufferSize + 1); + QVERIFY(device.sendBufferSize() > bufferSize); + +} + +//--------------------------------------------------------------------------- +void tst_QNativeSocketEngine::tooManySockets() +{ +#if defined Q_OS_WIN + QSKIP("Certain windows machines suffocate and spend too much time in this test.", SkipAll); +#endif + QList sockets; + QNativeSocketEngine *socketLayer = 0; + for (;;) { + socketLayer = new QNativeSocketEngine; + sockets.append(socketLayer); + + if (!socketLayer->initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)) + break; + } + + QCOMPARE(socketLayer->error(), QAbstractSocket::SocketResourceError); + + qDeleteAll(sockets); +} + +//--------------------------------------------------------------------------- +void tst_QNativeSocketEngine::bind() +{ +#if !defined Q_OS_WIN && !defined Q_OS_SYMBIAN + QNativeSocketEngine binder; + QVERIFY(binder.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); + QVERIFY(!binder.bind(QHostAddress::Any, 82)); + QVERIFY(binder.error() == QAbstractSocket::SocketAccessError); +#endif + + QNativeSocketEngine binder2; + QVERIFY(binder2.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); + QVERIFY(binder2.bind(QHostAddress::Any, 31180)); + + QNativeSocketEngine binder3; + QVERIFY(binder3.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); + QVERIFY(!binder3.bind(QHostAddress::Any, 31180)); + +#ifdef SYMBIAN_WINSOCK_CONNECTIVITY + qDebug("On Symbian Emulator (WinSock) we get EADDRNOTAVAIL instead of EADDRINUSE"); + QVERIFY(binder3.error() == QAbstractSocket::SocketAddressNotAvailableError); +#else + QVERIFY(binder3.error() == QAbstractSocket::AddressInUseError); +#endif +} + +//--------------------------------------------------------------------------- +void tst_QNativeSocketEngine::networkError() +{ + QNativeSocketEngine client; + + QVERIFY(client.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); + + const bool isConnected = client.connectToHost(QtNetworkSettings::serverIP(), 143); + if (!isConnected) { + QVERIFY(client.state() == QAbstractSocket::ConnectingState); + QVERIFY(client.waitForWrite()); + QVERIFY(client.state() == QAbstractSocket::ConnectedState); + } + QVERIFY(client.state() == QAbstractSocket::ConnectedState); + + // An unexpected network error! +#ifdef Q_OS_WIN + // could use shutdown to produce different errors + ::closesocket(client.socketDescriptor()); +#else + ::close(client.socketDescriptor()); +#endif + + QVERIFY(client.read(0, 0) == -1); +} + +//--------------------------------------------------------------------------- +void tst_QNativeSocketEngine::setSocketDescriptor() +{ + QNativeSocketEngine socket1; + QVERIFY(socket1.initialize(QAbstractSocket::TcpSocket)); + + QNativeSocketEngine socket2; + QVERIFY(socket2.initialize(socket1.socketDescriptor())); +} + +//--------------------------------------------------------------------------- +void tst_QNativeSocketEngine::invalidSend() +{ + QNativeSocketEngine socket; + QVERIFY(socket.initialize(QAbstractSocket::TcpSocket)); + + QTest::ignoreMessage(QtWarningMsg, "QNativeSocketEngine::writeDatagram() was" + " called by a socket other than QAbstractSocket::UdpSocket"); + QCOMPARE(socket.writeDatagram("hei", 3, QHostAddress::LocalHost, 143), + (qlonglong) -1); +} + +//--------------------------------------------------------------------------- +void tst_QNativeSocketEngine::receiveUrgentData() +{ + QNativeSocketEngine server; + + QVERIFY(server.initialize(QAbstractSocket::TcpSocket)); + + // Bind to any port on all interfaces + QVERIFY(server.bind(QHostAddress("0.0.0.0"), 0)); + QVERIFY(server.state() == QAbstractSocket::BoundState); + quint16 port = server.localPort(); + + QVERIFY(server.listen()); + QVERIFY(server.state() == QAbstractSocket::ListeningState); + + QNativeSocketEngine client; + QVERIFY(client.initialize(QAbstractSocket::TcpSocket)); + + if (!client.connectToHost(QHostAddress("127.0.0.1"), port)) { + QVERIFY(client.state() == QAbstractSocket::ConnectingState); + QVERIFY(client.waitForWrite()); + QVERIFY(client.state() == QAbstractSocket::ConnectedState); + } + + int socketDescriptor = server.accept(); + QVERIFY(socketDescriptor > 0); + + QNativeSocketEngine serverSocket; + QVERIFY(serverSocket.initialize(socketDescriptor)); + QVERIFY(serverSocket.state() == QAbstractSocket::ConnectedState); + + char msg; + int available; + QByteArray response; + +#if defined Q_OS_HPUX + QSKIP("Native OOB data test doesn't work on HP-UX.", SkipAll); +#elif defined (Q_OS_WINCE) + QSKIP("Native OOB data test doesn't work on WinCE.", SkipAll); +#endif + + // The server sends an urgent message + msg = 'Q'; + QCOMPARE(int(::send(socketDescriptor, &msg, sizeof(msg), MSG_OOB)), 1); + + // The client receives the urgent message + QVERIFY(client.waitForRead()); + available = client.bytesAvailable(); + QCOMPARE(available, 1); + response.resize(available); + QCOMPARE(client.read(response.data(), response.size()), qint64(1)); + QCOMPARE(response.at(0), msg); + + // The client sends an urgent message + msg = 'T'; + int clientDescriptor = client.socketDescriptor(); + QCOMPARE(int(::send(clientDescriptor, &msg, sizeof(msg), MSG_OOB)), 1); + + // The server receives the urgent message + QVERIFY(serverSocket.waitForRead()); + available = serverSocket.bytesAvailable(); + QCOMPARE(available, 1); + response.resize(available); + QCOMPARE(serverSocket.read(response.data(), response.size()), qint64(1)); + QCOMPARE(response.at(0), msg); + +} + +QTEST_MAIN(tst_QNativeSocketEngine) +#include "tst_qnativesocketengine.moc" diff --git a/tests/auto/qnativesocketengine/.gitignore b/tests/auto/qnativesocketengine/.gitignore deleted file mode 100644 index 4700e5e..0000000 --- a/tests/auto/qnativesocketengine/.gitignore +++ /dev/null @@ -1 +0,0 @@ -tst_qnativesocketengine diff --git a/tests/auto/qnativesocketengine/qnativesocketengine.pro b/tests/auto/qnativesocketengine/qnativesocketengine.pro deleted file mode 100644 index 0275d37..0000000 --- a/tests/auto/qnativesocketengine/qnativesocketengine.pro +++ /dev/null @@ -1,13 +0,0 @@ -load(qttest_p4) -SOURCES += tst_qnativesocketengine.cpp - -include(../qnativesocketengine/qsocketengine.pri) - -requires(contains(QT_CONFIG,private_tests)) - -MOC_DIR=tmp - -QT = core network - -symbian: TARGET.CAPABILITY = NetworkServices - diff --git a/tests/auto/qnativesocketengine/qsocketengine.pri b/tests/auto/qnativesocketengine/qsocketengine.pri deleted file mode 100644 index 15f31fd..0000000 --- a/tests/auto/qnativesocketengine/qsocketengine.pri +++ /dev/null @@ -1,19 +0,0 @@ -QT += network - -QNETWORK_SRC = $$QT_SOURCE_TREE/src/network - -INCLUDEPATH += $$QNETWORK_SRC - -win32 { - wince*: { - LIBS += -lws2 - } else { - LIBS += -lws2_32 - } -} - -unix:contains(QT_CONFIG, reduce_exports) { - SOURCES += $$QNETWORK_SRC/socket/qnativesocketengine_unix.cpp - SOURCES += $$QNETWORK_SRC/socket/qnativesocketengine.cpp - SOURCES += $$QNETWORK_SRC/socket/qabstractsocketengine.cpp -} diff --git a/tests/auto/qnativesocketengine/tst_qnativesocketengine.cpp b/tests/auto/qnativesocketengine/tst_qnativesocketengine.cpp deleted file mode 100644 index 2b0b632..0000000 --- a/tests/auto/qnativesocketengine/tst_qnativesocketengine.cpp +++ /dev/null @@ -1,705 +0,0 @@ -/**************************************************************************** -** -** 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 test suite 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 - -#ifdef Q_OS_WIN -#include -#endif - -#include - - -#include -#include - -#include -#include - -#ifdef Q_OS_UNIX -#include -#include -#include -#endif - -#include - - -#include - -#include "../network-settings.h" - -//TESTED_FILES=network/qnativesocketengine.cpp network/qnativesocketengine_p.h network/qnativesocketengine_unix.cpp - -class tst_QNativeSocketEngine : public QObject -{ - Q_OBJECT - -public: - tst_QNativeSocketEngine(); - virtual ~tst_QNativeSocketEngine(); - - -public slots: - void init(); - void cleanup(); -private slots: - void construction(); - void simpleConnectToIMAP(); - void udpLoopbackTest(); - void udpIPv6LoopbackTest(); - void broadcastTest(); - void serverTest(); - void udpLoopbackPerformance(); - void tcpLoopbackPerformance(); - void readWriteBufferSize(); - void tooManySockets(); - void bind(); - void networkError(); - void setSocketDescriptor(); - void invalidSend(); - void receiveUrgentData(); -}; - -tst_QNativeSocketEngine::tst_QNativeSocketEngine() -{ - Q_SET_DEFAULT_IAP -} - -tst_QNativeSocketEngine::~tst_QNativeSocketEngine() -{ -} - -void tst_QNativeSocketEngine::init() -{ -} - -void tst_QNativeSocketEngine::cleanup() -{ -} - -//--------------------------------------------------------------------------- -void tst_QNativeSocketEngine::construction() -{ - QNativeSocketEngine socketDevice; - - QVERIFY(!socketDevice.isValid()); - - // Initialize device - QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); - QVERIFY(socketDevice.isValid()); - QVERIFY(socketDevice.protocol() == QAbstractSocket::IPv4Protocol); - QVERIFY(socketDevice.socketType() == QAbstractSocket::TcpSocket); - QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState); - QVERIFY(socketDevice.socketDescriptor() != -1); - QVERIFY(socketDevice.localAddress() == QHostAddress()); - QVERIFY(socketDevice.localPort() == 0); - QVERIFY(socketDevice.peerAddress() == QHostAddress()); - QVERIFY(socketDevice.peerPort() == 0); - QVERIFY(socketDevice.error() == QAbstractSocket::UnknownSocketError); - - QTest::ignoreMessage(QtWarningMsg, "QNativeSocketEngine::bytesAvailable() was called in QAbstractSocket::UnconnectedState"); - QVERIFY(socketDevice.bytesAvailable() == 0); - - QTest::ignoreMessage(QtWarningMsg, "QNativeSocketEngine::hasPendingDatagrams() was called in QAbstractSocket::UnconnectedState"); - QVERIFY(!socketDevice.hasPendingDatagrams()); -} - -//--------------------------------------------------------------------------- -void tst_QNativeSocketEngine::simpleConnectToIMAP() -{ - QNativeSocketEngine socketDevice; - - // Initialize device - QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); - QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState); - - const bool isConnected = socketDevice.connectToHost(QtNetworkSettings::serverIP(), 143); - if (!isConnected) { - QVERIFY(socketDevice.state() == QAbstractSocket::ConnectingState); - QVERIFY(socketDevice.waitForWrite()); - QVERIFY(socketDevice.state() == QAbstractSocket::ConnectedState); - } - QVERIFY(socketDevice.state() == QAbstractSocket::ConnectedState); - QVERIFY(socketDevice.peerAddress() == QtNetworkSettings::serverIP()); - - // Wait for the greeting - QVERIFY(socketDevice.waitForRead()); - - // Read the greeting - qint64 available = socketDevice.bytesAvailable(); - QVERIFY(available > 0); - QByteArray array; - array.resize(available); - QVERIFY(socketDevice.read(array.data(), array.size()) == available); - - // Check that the greeting is what we expect it to be - QCOMPARE(array.constData(), QtNetworkSettings::expectedReplyIMAP().constData()); - - // Write a logout message - QByteArray array2 = "ZZZ LOGOUT\r\n"; - QVERIFY(socketDevice.write(array2.data(), - array2.size()) == array2.size()); - - // Wait for the response - QVERIFY(socketDevice.waitForRead()); - - available = socketDevice.bytesAvailable(); - QVERIFY(available > 0); - array.resize(available); - QVERIFY(socketDevice.read(array.data(), array.size()) == available); - - // Check that the greeting is what we expect it to be - QCOMPARE(array.constData(), - "* BYE LOGOUT received\r\n" - "ZZZ OK Completed\r\n"); - - // Wait for the response - QVERIFY(socketDevice.waitForRead()); - char c; - QVERIFY(socketDevice.read(&c, sizeof(c)) == -1); - QVERIFY(socketDevice.error() == QAbstractSocket::RemoteHostClosedError); - QVERIFY(socketDevice.state() == QAbstractSocket::UnconnectedState); -} - -//--------------------------------------------------------------------------- -void tst_QNativeSocketEngine::udpLoopbackTest() -{ -#ifdef SYMBIAN_WINSOCK_CONNECTIVITY - QSKIP("Not working on Emulator without WinPCAP", SkipAll); -#endif - QNativeSocketEngine udpSocket; - - // Initialize device #1 - QVERIFY(udpSocket.initialize(QAbstractSocket::UdpSocket)); - QVERIFY(udpSocket.isValid()); - QVERIFY(udpSocket.socketDescriptor() != -1); - QVERIFY(udpSocket.protocol() == QAbstractSocket::IPv4Protocol); - QVERIFY(udpSocket.socketType() == QAbstractSocket::UdpSocket); - QVERIFY(udpSocket.state() == QAbstractSocket::UnconnectedState); - - // Bind #1 to localhost - QVERIFY(udpSocket.bind(QHostAddress("127.0.0.1"), 0)); - QVERIFY(udpSocket.state() == QAbstractSocket::BoundState); - quint16 port = udpSocket.localPort(); - QVERIFY(port != 0); - - // Initialize device #2 - QNativeSocketEngine udpSocket2; - QVERIFY(udpSocket2.initialize(QAbstractSocket::UdpSocket)); - - // Connect device #2 to #1 - QVERIFY(udpSocket2.connectToHost(QHostAddress("127.0.0.1"), port)); - QVERIFY(udpSocket2.state() == QAbstractSocket::ConnectedState); - - // Write a message to #1 - QByteArray message1 = "hei der"; - QVERIFY(udpSocket2.write(message1.data(), - message1.size()) == message1.size()); - - // Read the message from #2 - QVERIFY(udpSocket.waitForRead()); - QVERIFY(udpSocket.hasPendingDatagrams()); - qint64 available = udpSocket.pendingDatagramSize(); - QVERIFY(available > 0); - QByteArray answer; - answer.resize(available); - QHostAddress senderAddress; - quint16 senderPort = 0; - QVERIFY(udpSocket.readDatagram(answer.data(), answer.size(), - &senderAddress, - &senderPort) == message1.size()); - QVERIFY(senderAddress == QHostAddress("127.0.0.1")); - QVERIFY(senderPort != 0); -} - -//--------------------------------------------------------------------------- -void tst_QNativeSocketEngine::udpIPv6LoopbackTest() -{ -#if defined(Q_OS_SYMBIAN) - QSKIP("Symbian: IPv6 is not yet supported", SkipAll); -#endif - QNativeSocketEngine udpSocket; - - // Initialize device #1 - bool init = udpSocket.initialize(QAbstractSocket::UdpSocket, QAbstractSocket::IPv6Protocol); - - if (!init) { - QVERIFY(udpSocket.error() == QAbstractSocket::UnsupportedSocketOperationError); - } else { - QVERIFY(udpSocket.protocol() == QAbstractSocket::IPv6Protocol); - - // Bind #1 to localhost - QVERIFY(udpSocket.bind(QHostAddress("::1"), 0)); - QVERIFY(udpSocket.state() == QAbstractSocket::BoundState); - quint16 port = udpSocket.localPort(); - QVERIFY(port != 0); - - // Initialize device #2 - QNativeSocketEngine udpSocket2; - QVERIFY(udpSocket2.initialize(QAbstractSocket::UdpSocket, QAbstractSocket::IPv6Protocol)); - - // Connect device #2 to #1 - QVERIFY(udpSocket2.connectToHost(QHostAddress("::1"), port)); - QVERIFY(udpSocket2.state() == QAbstractSocket::ConnectedState); - - // Write a message to #1 - QByteArray message1 = "hei der"; - QVERIFY(udpSocket2.write(message1.data(), - message1.size()) == message1.size()); - - // Read the message from #2 - QVERIFY(udpSocket.waitForRead()); - QVERIFY(udpSocket.hasPendingDatagrams()); - qint64 available = udpSocket.pendingDatagramSize(); - QVERIFY(available > 0); - QByteArray answer; - answer.resize(available); - QHostAddress senderAddress; - quint16 senderPort = 0; - QVERIFY(udpSocket.readDatagram(answer.data(), answer.size(), - &senderAddress, - &senderPort) == message1.size()); - QVERIFY(senderAddress == QHostAddress("::1")); - QVERIFY(senderPort != 0); - } -} - -//--------------------------------------------------------------------------- -void tst_QNativeSocketEngine::broadcastTest() -{ -#ifdef Q_OS_AIX - QSKIP("Broadcast does not work on darko", SkipAll); -#endif - QNativeSocketEngine broadcastSocket; - - // Initialize a regular Udp socket - QVERIFY(broadcastSocket.initialize(QAbstractSocket::UdpSocket)); - - // Bind to any port on all interfaces - QVERIFY(broadcastSocket.bind(QHostAddress::Any, 0)); - QVERIFY(broadcastSocket.state() == QAbstractSocket::BoundState); - quint16 port = broadcastSocket.localPort(); - QVERIFY(port > 0); - - // Broadcast an inappropriate troll message - QByteArray trollMessage - = "MOOT wtf is a MOOT? talk english not your sutpiD ENGLISH."; - QVERIFY(broadcastSocket.writeDatagram(trollMessage.data(), - trollMessage.size(), - QHostAddress::Broadcast, - port) == trollMessage.size()); - - // Wait until we receive it ourselves -#if defined(Q_OS_FREEBSD) - QEXPECT_FAIL("", "Broadcasting to 255.255.255.255 does not work on FreeBSD", Abort); -#endif - QVERIFY(broadcastSocket.waitForRead()); - QVERIFY(broadcastSocket.hasPendingDatagrams()); - - qlonglong available = broadcastSocket.pendingDatagramSize(); - QByteArray response; - response.resize(available); - QVERIFY(broadcastSocket.readDatagram(response.data(), response.size()) - == response.size()); - QCOMPARE(response, trollMessage); - -} - -//--------------------------------------------------------------------------- -void tst_QNativeSocketEngine::serverTest() -{ - QNativeSocketEngine server; - - // Initialize a Tcp socket - QVERIFY(server.initialize(QAbstractSocket::TcpSocket)); - - // Bind to any port on all interfaces - QVERIFY(server.bind(QHostAddress("0.0.0.0"), 0)); - QVERIFY(server.state() == QAbstractSocket::BoundState); - quint16 port = server.localPort(); - - // Listen for incoming connections - QVERIFY(server.listen()); - QVERIFY(server.state() == QAbstractSocket::ListeningState); - - // Initialize a Tcp socket - QNativeSocketEngine client; - QVERIFY(client.initialize(QAbstractSocket::TcpSocket)); - if (!client.connectToHost(QHostAddress("127.0.0.1"), port)) { - QVERIFY(client.state() == QAbstractSocket::ConnectingState); - QVERIFY(client.waitForWrite()); - QVERIFY(client.state() == QAbstractSocket::ConnectedState); - } - - // The server accepts the connection - int socketDescriptor = server.accept(); - QVERIFY(socketDescriptor > 0); - - // A socket device is initialized on the server side, passing the - // socket descriptor from accept(). It's pre-connected. - QNativeSocketEngine serverSocket; - QVERIFY(serverSocket.initialize(socketDescriptor)); - QVERIFY(serverSocket.state() == QAbstractSocket::ConnectedState); - - // The server socket sends a greeting to the clietn - QByteArray greeting = "Greetings!"; - QVERIFY(serverSocket.write(greeting.data(), - greeting.size()) == greeting.size()); - - // The client waits for the greeting to arrive - QVERIFY(client.waitForRead()); - qint64 available = client.bytesAvailable(); - QVERIFY(available > 0); - - // The client reads the greeting and checks that it's correct - QByteArray response; - response.resize(available); - QVERIFY(client.read(response.data(), - response.size()) == response.size()); - QCOMPARE(response, greeting); -} - -//--------------------------------------------------------------------------- -void tst_QNativeSocketEngine::udpLoopbackPerformance() -{ -#ifdef SYMBIAN_WINSOCK_CONNECTIVITY - QSKIP("Not working on Emulator without WinPCAP", SkipAll); -#endif - QNativeSocketEngine udpSocket; - - // Initialize device #1 - QVERIFY(udpSocket.initialize(QAbstractSocket::UdpSocket)); - QVERIFY(udpSocket.isValid()); - QVERIFY(udpSocket.socketDescriptor() != -1); - QVERIFY(udpSocket.protocol() == QAbstractSocket::IPv4Protocol); - QVERIFY(udpSocket.socketType() == QAbstractSocket::UdpSocket); - QVERIFY(udpSocket.state() == QAbstractSocket::UnconnectedState); - - // Bind #1 to localhost - QVERIFY(udpSocket.bind(QHostAddress("127.0.0.1"), 0)); - QVERIFY(udpSocket.state() == QAbstractSocket::BoundState); - quint16 port = udpSocket.localPort(); - QVERIFY(port != 0); - - // Initialize device #2 - QNativeSocketEngine udpSocket2; - QVERIFY(udpSocket2.initialize(QAbstractSocket::UdpSocket)); - - // Connect device #2 to #1 - QVERIFY(udpSocket2.connectToHost(QHostAddress("127.0.0.1"), port)); - QVERIFY(udpSocket2.state() == QAbstractSocket::ConnectedState); - - const int messageSize = 8192; - QByteArray message1(messageSize, '@'); - QByteArray answer(messageSize, '@'); - - QHostAddress localhost = QHostAddress::LocalHost; - - qlonglong readBytes = 0; - QTime timer; - timer.start(); - while (timer.elapsed() < 5000) { - udpSocket2.write(message1.data(), message1.size()); - udpSocket.waitForRead(); - while (udpSocket.hasPendingDatagrams()) { - readBytes += (qlonglong) udpSocket.readDatagram(answer.data(), - answer.size()); - } - } - - qDebug("\t\t%.1fMB/%.1fs: %.1fMB/s", - readBytes / (1024.0 * 1024.0), - timer.elapsed() / 1024.0, - (readBytes / (timer.elapsed() / 1000.0)) / (1024 * 1024)); -} - -//--------------------------------------------------------------------------- -void tst_QNativeSocketEngine::tcpLoopbackPerformance() -{ - QNativeSocketEngine server; - - // Initialize a Tcp socket - QVERIFY(server.initialize(QAbstractSocket::TcpSocket)); - - // Bind to any port on all interfaces - QVERIFY(server.bind(QHostAddress("0.0.0.0"), 0)); - QVERIFY(server.state() == QAbstractSocket::BoundState); - quint16 port = server.localPort(); - - // Listen for incoming connections - QVERIFY(server.listen()); - QVERIFY(server.state() == QAbstractSocket::ListeningState); - - // Initialize a Tcp socket - QNativeSocketEngine client; - QVERIFY(client.initialize(QAbstractSocket::TcpSocket)); - - // Connect to our server - if (!client.connectToHost(QHostAddress("127.0.0.1"), port)) { - QVERIFY(client.state() == QAbstractSocket::ConnectingState); - QVERIFY(client.waitForWrite()); - QVERIFY(client.state() == QAbstractSocket::ConnectedState); - } - - // The server accepts the connectio - int socketDescriptor = server.accept(); - QVERIFY(socketDescriptor > 0); - - // A socket device is initialized on the server side, passing the - // socket descriptor from accept(). It's pre-connected. - QNativeSocketEngine serverSocket; - QVERIFY(serverSocket.initialize(socketDescriptor)); - QVERIFY(serverSocket.state() == QAbstractSocket::ConnectedState); - - const int messageSize = 1024 * 256; - QByteArray message1(messageSize, '@'); - QByteArray answer(messageSize, '@'); - - QTime timer; - timer.start(); - qlonglong readBytes = 0; - while (timer.elapsed() < 5000) { - qlonglong written = serverSocket.write(message1.data(), message1.size()); - while (written > 0) { - client.waitForRead(); - if (client.bytesAvailable() > 0) { - qlonglong readNow = client.read(answer.data(), answer.size()); - written -= readNow; - readBytes += readNow; - } - } - } - - qDebug("\t\t%.1fMB/%.1fs: %.1fMB/s", - readBytes / (1024.0 * 1024.0), - timer.elapsed() / 1024.0, - (readBytes / (timer.elapsed() / 1000.0)) / (1024 * 1024)); -} - -//--------------------------------------------------------------------------- -void tst_QNativeSocketEngine::readWriteBufferSize() -{ - QNativeSocketEngine device; - - QVERIFY(device.initialize(QAbstractSocket::TcpSocket)); - - qint64 bufferSize = device.receiveBufferSize(); - QVERIFY(bufferSize != -1); - device.setReceiveBufferSize(bufferSize + 1); -#if defined(Q_OS_WINCE) - QEXPECT_FAIL(0, "Not supported by default on WinCE", Continue); -#endif - QVERIFY(device.receiveBufferSize() > bufferSize); - - bufferSize = device.sendBufferSize(); - QVERIFY(bufferSize != -1); - device.setSendBufferSize(bufferSize + 1); - QVERIFY(device.sendBufferSize() > bufferSize); - -} - -//--------------------------------------------------------------------------- -void tst_QNativeSocketEngine::tooManySockets() -{ -#if defined Q_OS_WIN - QSKIP("Certain windows machines suffocate and spend too much time in this test.", SkipAll); -#endif - QList sockets; - QNativeSocketEngine *socketLayer = 0; - for (;;) { - socketLayer = new QNativeSocketEngine; - sockets.append(socketLayer); - - if (!socketLayer->initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)) - break; - } - - QCOMPARE(socketLayer->error(), QAbstractSocket::SocketResourceError); - - qDeleteAll(sockets); -} - -//--------------------------------------------------------------------------- -void tst_QNativeSocketEngine::bind() -{ -#if !defined Q_OS_WIN && !defined Q_OS_SYMBIAN - QNativeSocketEngine binder; - QVERIFY(binder.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); - QVERIFY(!binder.bind(QHostAddress::Any, 82)); - QVERIFY(binder.error() == QAbstractSocket::SocketAccessError); -#endif - - QNativeSocketEngine binder2; - QVERIFY(binder2.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); - QVERIFY(binder2.bind(QHostAddress::Any, 31180)); - - QNativeSocketEngine binder3; - QVERIFY(binder3.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); - QVERIFY(!binder3.bind(QHostAddress::Any, 31180)); - -#ifdef SYMBIAN_WINSOCK_CONNECTIVITY - qDebug("On Symbian Emulator (WinSock) we get EADDRNOTAVAIL instead of EADDRINUSE"); - QVERIFY(binder3.error() == QAbstractSocket::SocketAddressNotAvailableError); -#else - QVERIFY(binder3.error() == QAbstractSocket::AddressInUseError); -#endif -} - -//--------------------------------------------------------------------------- -void tst_QNativeSocketEngine::networkError() -{ - QNativeSocketEngine client; - - QVERIFY(client.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); - - const bool isConnected = client.connectToHost(QtNetworkSettings::serverIP(), 143); - if (!isConnected) { - QVERIFY(client.state() == QAbstractSocket::ConnectingState); - QVERIFY(client.waitForWrite()); - QVERIFY(client.state() == QAbstractSocket::ConnectedState); - } - QVERIFY(client.state() == QAbstractSocket::ConnectedState); - - // An unexpected network error! -#ifdef Q_OS_WIN - // could use shutdown to produce different errors - ::closesocket(client.socketDescriptor()); -#else - ::close(client.socketDescriptor()); -#endif - - QVERIFY(client.read(0, 0) == -1); -} - -//--------------------------------------------------------------------------- -void tst_QNativeSocketEngine::setSocketDescriptor() -{ - QNativeSocketEngine socket1; - QVERIFY(socket1.initialize(QAbstractSocket::TcpSocket)); - - QNativeSocketEngine socket2; - QVERIFY(socket2.initialize(socket1.socketDescriptor())); -} - -//--------------------------------------------------------------------------- -void tst_QNativeSocketEngine::invalidSend() -{ - QNativeSocketEngine socket; - QVERIFY(socket.initialize(QAbstractSocket::TcpSocket)); - - QTest::ignoreMessage(QtWarningMsg, "QNativeSocketEngine::writeDatagram() was" - " called by a socket other than QAbstractSocket::UdpSocket"); - QCOMPARE(socket.writeDatagram("hei", 3, QHostAddress::LocalHost, 143), - (qlonglong) -1); -} - -//--------------------------------------------------------------------------- -void tst_QNativeSocketEngine::receiveUrgentData() -{ - QNativeSocketEngine server; - - QVERIFY(server.initialize(QAbstractSocket::TcpSocket)); - - // Bind to any port on all interfaces - QVERIFY(server.bind(QHostAddress("0.0.0.0"), 0)); - QVERIFY(server.state() == QAbstractSocket::BoundState); - quint16 port = server.localPort(); - - QVERIFY(server.listen()); - QVERIFY(server.state() == QAbstractSocket::ListeningState); - - QNativeSocketEngine client; - QVERIFY(client.initialize(QAbstractSocket::TcpSocket)); - - if (!client.connectToHost(QHostAddress("127.0.0.1"), port)) { - QVERIFY(client.state() == QAbstractSocket::ConnectingState); - QVERIFY(client.waitForWrite()); - QVERIFY(client.state() == QAbstractSocket::ConnectedState); - } - - int socketDescriptor = server.accept(); - QVERIFY(socketDescriptor > 0); - - QNativeSocketEngine serverSocket; - QVERIFY(serverSocket.initialize(socketDescriptor)); - QVERIFY(serverSocket.state() == QAbstractSocket::ConnectedState); - - char msg; - int available; - QByteArray response; - -#if defined Q_OS_HPUX - QSKIP("Native OOB data test doesn't work on HP-UX.", SkipAll); -#elif defined (Q_OS_WINCE) - QSKIP("Native OOB data test doesn't work on WinCE.", SkipAll); -#endif - - // The server sends an urgent message - msg = 'Q'; - QCOMPARE(int(::send(socketDescriptor, &msg, sizeof(msg), MSG_OOB)), 1); - - // The client receives the urgent message - QVERIFY(client.waitForRead()); - available = client.bytesAvailable(); - QCOMPARE(available, 1); - response.resize(available); - QCOMPARE(client.read(response.data(), response.size()), qint64(1)); - QCOMPARE(response.at(0), msg); - - // The client sends an urgent message - msg = 'T'; - int clientDescriptor = client.socketDescriptor(); - QCOMPARE(int(::send(clientDescriptor, &msg, sizeof(msg), MSG_OOB)), 1); - - // The server receives the urgent message - QVERIFY(serverSocket.waitForRead()); - available = serverSocket.bytesAvailable(); - QCOMPARE(available, 1); - response.resize(available); - QCOMPARE(serverSocket.read(response.data(), response.size()), qint64(1)); - QCOMPARE(response.at(0), msg); - -} - -QTEST_MAIN(tst_QNativeSocketEngine) -#include "tst_qnativesocketengine.moc" -- cgit v0.12 From 94226b6865615e844c46c6c068e3d4e9a9eb2068 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Thu, 9 Dec 2010 15:29:30 +0100 Subject: Make tst_platformsocketengine work Compile and instanciate the right engine. Reviewed-by: Shane Kearns --- tests/auto/network.pro | 4 +- tests/auto/platformsocketengine/.gitignore | 2 +- .../platformsocketengine/platformsocketengine.pro | 6 +- .../tst_platformsocketengine.cpp | 114 +++++++++++---------- tests/auto/qhttpsocketengine/qhttpsocketengine.pro | 2 +- .../qsocks5socketengine/qsocks5socketengine.pro | 2 +- 6 files changed, 68 insertions(+), 62 deletions(-) diff --git a/tests/auto/network.pro b/tests/auto/network.pro index 31c754c..5bf6a92 100644 --- a/tests/auto/network.pro +++ b/tests/auto/network.pro @@ -16,7 +16,7 @@ SUBDIRS=\ qhttpnetworkconnection \ qhttpnetworkreply \ qhttpsocketengine \ - qnativesocketengine \ + platformsocketengine \ qnetworkaccessmanager \ qnetworkaddressentry \ qnetworkconfiguration \ @@ -40,7 +40,7 @@ SUBDIRS=\ qauthenticator \ qhttpnetworkconnection \ qhttpnetworkreply \ - qnativesocketengine \ + platformsocketengine \ qsocketnotifier \ qsocks5socketengine \ diff --git a/tests/auto/platformsocketengine/.gitignore b/tests/auto/platformsocketengine/.gitignore index 4700e5e..afe9389 100644 --- a/tests/auto/platformsocketengine/.gitignore +++ b/tests/auto/platformsocketengine/.gitignore @@ -1 +1 @@ -tst_qnativesocketengine +tst_platformsocketengine diff --git a/tests/auto/platformsocketengine/platformsocketengine.pro b/tests/auto/platformsocketengine/platformsocketengine.pro index 0275d37..04816af 100644 --- a/tests/auto/platformsocketengine/platformsocketengine.pro +++ b/tests/auto/platformsocketengine/platformsocketengine.pro @@ -1,7 +1,7 @@ load(qttest_p4) -SOURCES += tst_qnativesocketengine.cpp +SOURCES += tst_platformsocketengine.cpp -include(../qnativesocketengine/qsocketengine.pri) +include(../platformsocketengine/platformsocketengine.pri) requires(contains(QT_CONFIG,private_tests)) @@ -10,4 +10,4 @@ MOC_DIR=tmp QT = core network symbian: TARGET.CAPABILITY = NetworkServices - +symbian: INCLUDEPATH += $$OS_LAYER_SYSTEMINCLUDE \ No newline at end of file diff --git a/tests/auto/platformsocketengine/tst_platformsocketengine.cpp b/tests/auto/platformsocketengine/tst_platformsocketengine.cpp index 2b0b632..bede360 100644 --- a/tests/auto/platformsocketengine/tst_platformsocketengine.cpp +++ b/tests/auto/platformsocketengine/tst_platformsocketengine.cpp @@ -50,7 +50,6 @@ #include -#include #include #include @@ -63,6 +62,13 @@ #include +#ifdef Q_OS_SYMBIAN +#define PLATFORMSOCKETENGINE QSymbianSocketEngine +#include +#else +#define PLATFORMSOCKETENGINE QNativeSocketEngine +#include +#endif #include @@ -70,13 +76,13 @@ //TESTED_FILES=network/qnativesocketengine.cpp network/qnativesocketengine_p.h network/qnativesocketengine_unix.cpp -class tst_QNativeSocketEngine : public QObject +class tst_PlatformSocketEngine : public QObject { Q_OBJECT public: - tst_QNativeSocketEngine(); - virtual ~tst_QNativeSocketEngine(); + tst_PlatformSocketEngine(); + virtual ~tst_PlatformSocketEngine(); public slots: @@ -100,27 +106,27 @@ private slots: void receiveUrgentData(); }; -tst_QNativeSocketEngine::tst_QNativeSocketEngine() +tst_PlatformSocketEngine::tst_PlatformSocketEngine() { Q_SET_DEFAULT_IAP } -tst_QNativeSocketEngine::~tst_QNativeSocketEngine() +tst_PlatformSocketEngine::~tst_PlatformSocketEngine() { } -void tst_QNativeSocketEngine::init() +void tst_PlatformSocketEngine::init() { } -void tst_QNativeSocketEngine::cleanup() +void tst_PlatformSocketEngine::cleanup() { } //--------------------------------------------------------------------------- -void tst_QNativeSocketEngine::construction() +void tst_PlatformSocketEngine::construction() { - QNativeSocketEngine socketDevice; + PLATFORMSOCKETENGINE socketDevice; QVERIFY(!socketDevice.isValid()); @@ -145,9 +151,9 @@ void tst_QNativeSocketEngine::construction() } //--------------------------------------------------------------------------- -void tst_QNativeSocketEngine::simpleConnectToIMAP() +void tst_PlatformSocketEngine::simpleConnectToIMAP() { - QNativeSocketEngine socketDevice; + PLATFORMSOCKETENGINE socketDevice; // Initialize device QVERIFY(socketDevice.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); @@ -202,12 +208,12 @@ void tst_QNativeSocketEngine::simpleConnectToIMAP() } //--------------------------------------------------------------------------- -void tst_QNativeSocketEngine::udpLoopbackTest() +void tst_PlatformSocketEngine::udpLoopbackTest() { #ifdef SYMBIAN_WINSOCK_CONNECTIVITY QSKIP("Not working on Emulator without WinPCAP", SkipAll); #endif - QNativeSocketEngine udpSocket; + PLATFORMSOCKETENGINE udpSocket; // Initialize device #1 QVERIFY(udpSocket.initialize(QAbstractSocket::UdpSocket)); @@ -224,7 +230,7 @@ void tst_QNativeSocketEngine::udpLoopbackTest() QVERIFY(port != 0); // Initialize device #2 - QNativeSocketEngine udpSocket2; + PLATFORMSOCKETENGINE udpSocket2; QVERIFY(udpSocket2.initialize(QAbstractSocket::UdpSocket)); // Connect device #2 to #1 @@ -253,12 +259,12 @@ void tst_QNativeSocketEngine::udpLoopbackTest() } //--------------------------------------------------------------------------- -void tst_QNativeSocketEngine::udpIPv6LoopbackTest() +void tst_PlatformSocketEngine::udpIPv6LoopbackTest() { #if defined(Q_OS_SYMBIAN) QSKIP("Symbian: IPv6 is not yet supported", SkipAll); #endif - QNativeSocketEngine udpSocket; + PLATFORMSOCKETENGINE udpSocket; // Initialize device #1 bool init = udpSocket.initialize(QAbstractSocket::UdpSocket, QAbstractSocket::IPv6Protocol); @@ -275,7 +281,7 @@ void tst_QNativeSocketEngine::udpIPv6LoopbackTest() QVERIFY(port != 0); // Initialize device #2 - QNativeSocketEngine udpSocket2; + PLATFORMSOCKETENGINE udpSocket2; QVERIFY(udpSocket2.initialize(QAbstractSocket::UdpSocket, QAbstractSocket::IPv6Protocol)); // Connect device #2 to #1 @@ -305,12 +311,12 @@ void tst_QNativeSocketEngine::udpIPv6LoopbackTest() } //--------------------------------------------------------------------------- -void tst_QNativeSocketEngine::broadcastTest() +void tst_PlatformSocketEngine::broadcastTest() { #ifdef Q_OS_AIX QSKIP("Broadcast does not work on darko", SkipAll); #endif - QNativeSocketEngine broadcastSocket; + PLATFORMSOCKETENGINE broadcastSocket; // Initialize a regular Udp socket QVERIFY(broadcastSocket.initialize(QAbstractSocket::UdpSocket)); @@ -346,9 +352,9 @@ void tst_QNativeSocketEngine::broadcastTest() } //--------------------------------------------------------------------------- -void tst_QNativeSocketEngine::serverTest() +void tst_PlatformSocketEngine::serverTest() { - QNativeSocketEngine server; + PLATFORMSOCKETENGINE server; // Initialize a Tcp socket QVERIFY(server.initialize(QAbstractSocket::TcpSocket)); @@ -363,7 +369,7 @@ void tst_QNativeSocketEngine::serverTest() QVERIFY(server.state() == QAbstractSocket::ListeningState); // Initialize a Tcp socket - QNativeSocketEngine client; + PLATFORMSOCKETENGINE client; QVERIFY(client.initialize(QAbstractSocket::TcpSocket)); if (!client.connectToHost(QHostAddress("127.0.0.1"), port)) { QVERIFY(client.state() == QAbstractSocket::ConnectingState); @@ -377,7 +383,7 @@ void tst_QNativeSocketEngine::serverTest() // A socket device is initialized on the server side, passing the // socket descriptor from accept(). It's pre-connected. - QNativeSocketEngine serverSocket; + PLATFORMSOCKETENGINE serverSocket; QVERIFY(serverSocket.initialize(socketDescriptor)); QVERIFY(serverSocket.state() == QAbstractSocket::ConnectedState); @@ -400,12 +406,12 @@ void tst_QNativeSocketEngine::serverTest() } //--------------------------------------------------------------------------- -void tst_QNativeSocketEngine::udpLoopbackPerformance() +void tst_PlatformSocketEngine::udpLoopbackPerformance() { #ifdef SYMBIAN_WINSOCK_CONNECTIVITY QSKIP("Not working on Emulator without WinPCAP", SkipAll); #endif - QNativeSocketEngine udpSocket; + PLATFORMSOCKETENGINE udpSocket; // Initialize device #1 QVERIFY(udpSocket.initialize(QAbstractSocket::UdpSocket)); @@ -422,7 +428,7 @@ void tst_QNativeSocketEngine::udpLoopbackPerformance() QVERIFY(port != 0); // Initialize device #2 - QNativeSocketEngine udpSocket2; + PLATFORMSOCKETENGINE udpSocket2; QVERIFY(udpSocket2.initialize(QAbstractSocket::UdpSocket)); // Connect device #2 to #1 @@ -454,9 +460,9 @@ void tst_QNativeSocketEngine::udpLoopbackPerformance() } //--------------------------------------------------------------------------- -void tst_QNativeSocketEngine::tcpLoopbackPerformance() +void tst_PlatformSocketEngine::tcpLoopbackPerformance() { - QNativeSocketEngine server; + PLATFORMSOCKETENGINE server; // Initialize a Tcp socket QVERIFY(server.initialize(QAbstractSocket::TcpSocket)); @@ -471,7 +477,7 @@ void tst_QNativeSocketEngine::tcpLoopbackPerformance() QVERIFY(server.state() == QAbstractSocket::ListeningState); // Initialize a Tcp socket - QNativeSocketEngine client; + PLATFORMSOCKETENGINE client; QVERIFY(client.initialize(QAbstractSocket::TcpSocket)); // Connect to our server @@ -487,7 +493,7 @@ void tst_QNativeSocketEngine::tcpLoopbackPerformance() // A socket device is initialized on the server side, passing the // socket descriptor from accept(). It's pre-connected. - QNativeSocketEngine serverSocket; + PLATFORMSOCKETENGINE serverSocket; QVERIFY(serverSocket.initialize(socketDescriptor)); QVERIFY(serverSocket.state() == QAbstractSocket::ConnectedState); @@ -517,9 +523,9 @@ void tst_QNativeSocketEngine::tcpLoopbackPerformance() } //--------------------------------------------------------------------------- -void tst_QNativeSocketEngine::readWriteBufferSize() +void tst_PlatformSocketEngine::readWriteBufferSize() { - QNativeSocketEngine device; + PLATFORMSOCKETENGINE device; QVERIFY(device.initialize(QAbstractSocket::TcpSocket)); @@ -539,15 +545,15 @@ void tst_QNativeSocketEngine::readWriteBufferSize() } //--------------------------------------------------------------------------- -void tst_QNativeSocketEngine::tooManySockets() +void tst_PlatformSocketEngine::tooManySockets() { #if defined Q_OS_WIN QSKIP("Certain windows machines suffocate and spend too much time in this test.", SkipAll); #endif - QList sockets; - QNativeSocketEngine *socketLayer = 0; + QList sockets; + PLATFORMSOCKETENGINE *socketLayer = 0; for (;;) { - socketLayer = new QNativeSocketEngine; + socketLayer = new PLATFORMSOCKETENGINE; sockets.append(socketLayer); if (!socketLayer->initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)) @@ -560,20 +566,20 @@ void tst_QNativeSocketEngine::tooManySockets() } //--------------------------------------------------------------------------- -void tst_QNativeSocketEngine::bind() +void tst_PlatformSocketEngine::bind() { #if !defined Q_OS_WIN && !defined Q_OS_SYMBIAN - QNativeSocketEngine binder; + PLATFORMSOCKETENGINE binder; QVERIFY(binder.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); QVERIFY(!binder.bind(QHostAddress::Any, 82)); QVERIFY(binder.error() == QAbstractSocket::SocketAccessError); #endif - QNativeSocketEngine binder2; + PLATFORMSOCKETENGINE binder2; QVERIFY(binder2.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); QVERIFY(binder2.bind(QHostAddress::Any, 31180)); - QNativeSocketEngine binder3; + PLATFORMSOCKETENGINE binder3; QVERIFY(binder3.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); QVERIFY(!binder3.bind(QHostAddress::Any, 31180)); @@ -586,9 +592,9 @@ void tst_QNativeSocketEngine::bind() } //--------------------------------------------------------------------------- -void tst_QNativeSocketEngine::networkError() +void tst_PlatformSocketEngine::networkError() { - QNativeSocketEngine client; + PLATFORMSOCKETENGINE client; QVERIFY(client.initialize(QAbstractSocket::TcpSocket, QAbstractSocket::IPv4Protocol)); @@ -612,19 +618,19 @@ void tst_QNativeSocketEngine::networkError() } //--------------------------------------------------------------------------- -void tst_QNativeSocketEngine::setSocketDescriptor() +void tst_PlatformSocketEngine::setSocketDescriptor() { - QNativeSocketEngine socket1; + PLATFORMSOCKETENGINE socket1; QVERIFY(socket1.initialize(QAbstractSocket::TcpSocket)); - QNativeSocketEngine socket2; + PLATFORMSOCKETENGINE socket2; QVERIFY(socket2.initialize(socket1.socketDescriptor())); } //--------------------------------------------------------------------------- -void tst_QNativeSocketEngine::invalidSend() +void tst_PlatformSocketEngine::invalidSend() { - QNativeSocketEngine socket; + PLATFORMSOCKETENGINE socket; QVERIFY(socket.initialize(QAbstractSocket::TcpSocket)); QTest::ignoreMessage(QtWarningMsg, "QNativeSocketEngine::writeDatagram() was" @@ -634,9 +640,9 @@ void tst_QNativeSocketEngine::invalidSend() } //--------------------------------------------------------------------------- -void tst_QNativeSocketEngine::receiveUrgentData() +void tst_PlatformSocketEngine::receiveUrgentData() { - QNativeSocketEngine server; + PLATFORMSOCKETENGINE server; QVERIFY(server.initialize(QAbstractSocket::TcpSocket)); @@ -648,7 +654,7 @@ void tst_QNativeSocketEngine::receiveUrgentData() QVERIFY(server.listen()); QVERIFY(server.state() == QAbstractSocket::ListeningState); - QNativeSocketEngine client; + PLATFORMSOCKETENGINE client; QVERIFY(client.initialize(QAbstractSocket::TcpSocket)); if (!client.connectToHost(QHostAddress("127.0.0.1"), port)) { @@ -660,7 +666,7 @@ void tst_QNativeSocketEngine::receiveUrgentData() int socketDescriptor = server.accept(); QVERIFY(socketDescriptor > 0); - QNativeSocketEngine serverSocket; + PLATFORMSOCKETENGINE serverSocket; QVERIFY(serverSocket.initialize(socketDescriptor)); QVERIFY(serverSocket.state() == QAbstractSocket::ConnectedState); @@ -701,5 +707,5 @@ void tst_QNativeSocketEngine::receiveUrgentData() } -QTEST_MAIN(tst_QNativeSocketEngine) -#include "tst_qnativesocketengine.moc" +QTEST_MAIN(tst_PlatformSocketEngine) +#include "tst_platformsocketengine.moc" diff --git a/tests/auto/qhttpsocketengine/qhttpsocketengine.pro b/tests/auto/qhttpsocketengine/qhttpsocketengine.pro index d76ebb6..6df6192 100644 --- a/tests/auto/qhttpsocketengine/qhttpsocketengine.pro +++ b/tests/auto/qhttpsocketengine/qhttpsocketengine.pro @@ -2,7 +2,7 @@ load(qttest_p4) SOURCES += tst_qhttpsocketengine.cpp -include(../qnativesocketengine/qsocketengine.pri) +include(../platformsocketengine/platformsocketengine.pri) MOC_DIR=tmp diff --git a/tests/auto/qsocks5socketengine/qsocks5socketengine.pro b/tests/auto/qsocks5socketengine/qsocks5socketengine.pro index 171d428..c82c62d 100644 --- a/tests/auto/qsocks5socketengine/qsocks5socketengine.pro +++ b/tests/auto/qsocks5socketengine/qsocks5socketengine.pro @@ -2,7 +2,7 @@ load(qttest_p4) SOURCES += tst_qsocks5socketengine.cpp -include(../qnativesocketengine/qsocketengine.pri) +include(../platformsocketengine/platformsocketengine.pri) MOC_DIR=tmp -- cgit v0.12 From 9bbe9bc76222fa6f89283d96cbd9e448e331f909 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Thu, 9 Dec 2010 15:57:23 +0100 Subject: QSymbianSocketEngine: Some missing functions --- src/network/socket/qsymbiansocketengine.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index 1490bdd..9eadf0a 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -465,6 +465,26 @@ int QSymbianSocketEngine::option(QAbstractSocketEngine::SocketOption opt) const return -1; } +qint64 QSymbianSocketEngine::receiveBufferSize() const +{ + return option(ReceiveBufferSocketOption); +} + +void QSymbianSocketEngine::setReceiveBufferSize(qint64 size) +{ + setOption(ReceiveBufferSocketOption, size); +} + +qint64 QSymbianSocketEngine::sendBufferSize() const +{ + return option(SendBufferSocketOption); +} + +void QSymbianSocketEngine::setSendBufferSize(qint64 size) +{ + setOption(SendBufferSocketOption, size); +} + bool QSymbianSocketEngine::connectToHostByName(const QString &name, quint16 port) { // FIXME for engines that support hostnames.. not for us then i guess. -- cgit v0.12 From 931b3189d727f25f97c84f33c1d5fddaf0538777 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Thu, 9 Dec 2010 16:08:43 +0000 Subject: Fix some crashes in the symbian socket engine Reviewed-by: Markus Goetz --- src/corelib/kernel/qeventdispatcher_symbian.cpp | 8 +- src/network/kernel/qhostinfo_symbian.cpp | 5 ++ src/network/socket/qsymbiansocketengine.cpp | 113 ++++++++++++++++++------ 3 files changed, 99 insertions(+), 27 deletions(-) diff --git a/src/corelib/kernel/qeventdispatcher_symbian.cpp b/src/corelib/kernel/qeventdispatcher_symbian.cpp index 55be6eb..f70080a 100644 --- a/src/corelib/kernel/qeventdispatcher_symbian.cpp +++ b/src/corelib/kernel/qeventdispatcher_symbian.cpp @@ -1026,14 +1026,17 @@ bool QEventDispatcherSymbian::hasPendingEvents() void QEventDispatcherSymbian::registerSocketNotifier ( QSocketNotifier * notifier ) { - QSocketActiveObject *socketAO = new QSocketActiveObject(this, notifier); + //TODO: just need to be able to do something when event loop has sockets disabled +/* QSocketActiveObject *socketAO = new QSocketActiveObject(this, notifier); Q_CHECK_PTR(socketAO); m_notifiers.insert(notifier, socketAO); - selectThread().requestSocketEvents(notifier, &socketAO->iStatus); + selectThread().requestSocketEvents(notifier, &socketAO->iStatus);*/ } void QEventDispatcherSymbian::unregisterSocketNotifier ( QSocketNotifier * notifier ) { + //TODO: just need to be able to do something when event loop has sockets disabled + /* if (m_selectThread) m_selectThread->cancelSocketEvents(notifier); if (m_notifiers.contains(notifier)) { @@ -1042,6 +1045,7 @@ void QEventDispatcherSymbian::unregisterSocketNotifier ( QSocketNotifier * notif sockObj->deleteLater(); m_notifiers.remove(notifier); } + */ } void QEventDispatcherSymbian::reactivateSocketNotifier(QSocketNotifier *notifier) diff --git a/src/network/kernel/qhostinfo_symbian.cpp b/src/network/kernel/qhostinfo_symbian.cpp index 287021f..e70f2ce 100644 --- a/src/network/kernel/qhostinfo_symbian.cpp +++ b/src/network/kernel/qhostinfo_symbian.cpp @@ -89,6 +89,11 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) } */ + //TODO: HACK to return qt-test-server's ip + QList addresses; + addresses.append(QHostAddress("192.168.1.8")); + results.setHostName(hostName); + results.setAddresses(addresses); return results; } diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index 9eadf0a..b92b3bc 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -206,7 +206,8 @@ QSymbianSocketEnginePrivate::QSymbianSocketEnginePrivate() : connection(QSymbianSocketManager::instance().defaultConnection()), readNotifier(0), writeNotifier(0), - exceptNotifier(0) + exceptNotifier(0), + asyncSelect(0) { } @@ -306,6 +307,11 @@ bool QSymbianSocketEngine::initialize(int socketDescriptor, QAbstractSocket::Soc if (isValid()) close(); + if(!QSymbianSocketManager::instance().lookupSocket(socketDescriptor, d->nativeSocket)) { + d->setError(QAbstractSocket::SocketResourceError, + QSymbianSocketEnginePrivate::InvalidSocketErrorString); + return false; + } d->socketDescriptor = socketDescriptor; // determine socket type and protocol @@ -666,9 +672,7 @@ int QSymbianSocketEngine::accept() qWarning("QSymbianSocketEnginePrivate::nativeAccept() - error %d", status.Int()); return 0; } - // FIXME Qt Handle of new socket must be retrieved from QSymbianSocketManager - // and then returned. Not the SubSessionHandle! Also set the socket to nonblocking. - return blankSocket.SubSessionHandle(); + return QSymbianSocketManager::instance().addSocket(blankSocket); } qint64 QSymbianSocketEngine::bytesAvailable() const @@ -854,18 +858,47 @@ void QSymbianSocketEngine::close() qDebug("QSymbianSocketEnginePrivate::nativeClose()"); #endif + if (d->readNotifier) + d->readNotifier->setEnabled(false); + if (d->writeNotifier) + d->writeNotifier->setEnabled(false); + if (d->exceptNotifier) + d->exceptNotifier->setEnabled(false); + if(d->asyncSelect) { + d->asyncSelect->deleteLater(); + d->asyncSelect = 0; + } + //TODO: call nativeSocket.Shutdown(EImmediate) in some cases? d->nativeSocket.Close(); QSymbianSocketManager::instance().removeSocket(d->nativeSocket); - - // FIXME set nativeSocket to 0 ? + d->socketDescriptor = -1; + + d->socketState = QAbstractSocket::UnconnectedState; + d->hasSetSocketError = false; + d->localPort = 0; + d->localAddress.clear(); + d->peerPort = 0; + d->peerAddress.clear(); + if (d->readNotifier) { + qDeleteInEventHandler(d->readNotifier); + d->readNotifier = 0; + } + if (d->writeNotifier) { + qDeleteInEventHandler(d->writeNotifier); + d->writeNotifier = 0; + } + if (d->exceptNotifier) { + qDeleteInEventHandler(d->exceptNotifier); + d->exceptNotifier = 0; + } } qint64 QSymbianSocketEngine::write(const char *data, qint64 len) { Q_D(QSymbianSocketEngine); TPtrC8 buffer((TUint8*)data, (int)len); - TSockXfrLength sentBytes; + TSockXfrLength sentBytes = 0; TRequestStatus status; //TODO: OMG sync send! d->nativeSocket.Send(buffer, 0, status, sentBytes); User::WaitForRequest(status); @@ -874,6 +907,7 @@ qint64 QSymbianSocketEngine::write(const char *data, qint64 len) if (err) { switch (err) { case KErrDisconnected: + case KErrEof: sentBytes = -1; d->setError(QAbstractSocket::RemoteHostClosedError, d->RemoteHostClosedErrorString); close(); @@ -882,9 +916,12 @@ qint64 QSymbianSocketEngine::write(const char *data, qint64 len) d->setError(QAbstractSocket::DatagramTooLargeError, d->DatagramTooLargeErrorString); break; case KErrWouldBlock: - sentBytes = 0; + break; default: - d->setError(QAbstractSocket::NetworkError, d->SendDatagramErrorString); + sentBytes = -1; + d->setError(err); + close(); + break; } } @@ -914,20 +951,13 @@ qint64 QSymbianSocketEngine::read(char *data, qint64 maxSize) TInt err = status.Int(); int r = received(); - if (err) { - switch(err) { - case KErrWouldBlock: - // No data was available for reading - r = -2; - break; - case KErrDisconnected: - r = 0; - break; - default: - r = -1; - //error string is now set in read(), not here in nativeRead() - break; - } + if (err == KErrWouldBlock) { + // No data was available for reading + r = -2; + } else if (err != KErrNone) { + d->setError(err); + close(); + r = -1; } #if defined (QNATIVESOCKETENGINE_DEBUG) @@ -1188,6 +1218,36 @@ void QSymbianSocketEnginePrivate::setError(QAbstractSocket::SocketError error, E } } +//TODO: use QSystemError class when file engine is merged to master +void QSymbianSocketEnginePrivate::setError(TInt symbianError) +{ + hasSetSocketError = true; + switch(symbianError) { + case KErrDisconnected: + case KErrEof: + setError(QAbstractSocket::RemoteHostClosedError, + QSymbianSocketEnginePrivate::RemoteHostClosedErrorString); + break; + case KErrNetUnreach: + setError(QAbstractSocket::NetworkError, + QSymbianSocketEnginePrivate::NetworkUnreachableErrorString); + break; + case KErrHostUnreach: + setError(QAbstractSocket::NetworkError, + QSymbianSocketEnginePrivate::HostUnreachableErrorString); + break; + case KErrNoProtocolOpt: + setError(QAbstractSocket::NetworkError, + QSymbianSocketEnginePrivate::ProtocolUnsupportedErrorString); + break; + default: + socketError = QAbstractSocket::NetworkError; + socketErrorString = QString::number(symbianError); + break; + } + +} + class QReadNotifier : public QSocketNotifier { friend class QAsyncSelect; @@ -1277,7 +1337,7 @@ void QSymbianSocketEngine::setWriteNotificationEnabled(bool enable) d->writeNotifier->setEnabled(enable); } else if (enable && d->threadData->eventDispatcher) { QWriteNotifier *wn = new QWriteNotifier(d->socketDescriptor, this); - d->readNotifier = wn; + d->writeNotifier = wn; if (!(d->asyncSelect)) d->asyncSelect = q_check_ptr(new QAsyncSelect(d->threadData->eventDispatcher, d->nativeSocket, this)); d->asyncSelect->setWriteNotifier(wn); @@ -1451,7 +1511,7 @@ void QAsyncSelect::RunL() QEvent e(QEvent::SockAct); iWriteN->event(&e); } - if ((m_selectBuf() && KSockSelectExcept) || iStatus != KErrNone) { + if ((m_selectBuf() & KSockSelectExcept) || iStatus != KErrNone) { QEvent e(QEvent::SockAct); iExcN->event(&e); } @@ -1463,6 +1523,9 @@ void QAsyncSelect::RunL() void QAsyncSelect::deleteLater() { if (m_inSocketEvent) { + iExcN = 0; + iReadN = 0; + iWriteN = 0; m_deleteLater = true; } else { delete this; -- cgit v0.12 From 9a565b61fc8fdb7dd786072a78e6ae903b59ded2 Mon Sep 17 00:00:00 2001 From: Aaron Tunney Date: Thu, 9 Dec 2010 18:03:58 +0000 Subject: QHostInfo: Symbian implementation for fromName() Reviewed-By: Markus Goetz --- src/network/kernel/qhostinfo_symbian.cpp | 106 ++++++++++++++++++++++++++----- 1 file changed, 91 insertions(+), 15 deletions(-) diff --git a/src/network/kernel/qhostinfo_symbian.cpp b/src/network/kernel/qhostinfo_symbian.cpp index e70f2ce..fbd7fe9 100644 --- a/src/network/kernel/qhostinfo_symbian.cpp +++ b/src/network/kernel/qhostinfo_symbian.cpp @@ -40,19 +40,44 @@ ****************************************************************************/ //#define QHOSTINFO_DEBUG + +// Symbian Headers +#include +#include + +// Qt Headers #include #include +#include #include "qplatformdefs.h" #include "qhostinfo_p.h" +#include QT_BEGIN_NAMESPACE + QHostInfo QHostInfoAgent::fromName(const QString &hostName) { QHostInfo results; + // Connect to ESOCK + RSocketServ socketServ(qt_symbianGetSocketServer()); + RHostResolver hostResolver; + + // Will return both IPv4 and IPv6 + // TODO: Pass RHostResolver.Open() the global RConnection + int err = hostResolver.Open(socketServ, KAfInet, KProtocolInetUdp); + if (err) { + results.setError(QHostInfo::UnknownError); + results.setErrorString(tr("Symbian error code: %1").arg(err)); + + return results; + } + + TNameEntry nameResult; + #if defined(QHOSTINFO_DEBUG) qDebug("QHostInfoAgent::fromName(%s) looking up...", hostName.toLatin1().constData()); @@ -61,8 +86,26 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) QHostAddress address; if (address.setAddress(hostName)) { // Reverse lookup - // TODO - results.setHostName("assume.it.works"); + + TInetAddr IpAdd; + IpAdd.Input(qt_QString2TPtrC(hostName)); + + // Synchronous request. nameResult returns Host Name. + hostResolver.GetByAddress(IpAdd, nameResult); + if (err) { + // TODO - Could there be other errors? Symbian docs don't say. + if (err = KErrNotFound) { + results.setError(QHostInfo::HostNotFound); + results.setErrorString(tr("Host not found")); + } else { + results.setError(QHostInfo::UnknownError); + results.setErrorString(tr("Symbian error code: %1").arg(err)); + } + + return results; + } + + results.setHostName(qt_TDesC2QString(nameResult().iName)); results.setAddresses(QList() << address); return results; } @@ -78,32 +121,65 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) return results; } - // Call getaddrinfo, and place all IPv4 addresses at the start and + + // Call RHostResolver::GetByAddress, and place all IPv4 addresses at the start and // the IPv6 addresses at the end of the address list in results. - /* - results.setError(QHostInfo::HostNotFound); - results.setErrorString(tr("Host not found")); - } else { - results.setError(QHostInfo::UnknownError); - results.setErrorString(QString::fromLocal8Bit(gai_strerror(result))); + + // Synchronous request. + err = hostResolver.GetByName(qt_QString2TPtrC(aceHostname), nameResult); + if (err) { + // TODO - Could there be other errors? Symbian docs don't say. + if (err = KErrNotFound) { + results.setError(QHostInfo::HostNotFound); + results.setErrorString(tr("Host not found")); + } else { + results.setError(QHostInfo::UnknownError); + results.setErrorString(tr("Symbian error code: %1").arg(err)); + } + + return results; } - */ - //TODO: HACK to return qt-test-server's ip - QList addresses; - addresses.append(QHostAddress("192.168.1.8")); - results.setHostName(hostName); - results.setAddresses(addresses); + QList hostAddresses; + + TInetAddr hostAdd = nameResult().iAddr; + TBuf<16> ipAddr; + // Fill ipAddr with the IP address from hostAdd + hostAdd.Output(ipAddr); + if (ipAddr.Length() > 0) + hostAddresses.append(QHostAddress(qt_TDesC2QString(ipAddr))); + + // Check if there's more than one IP address linkd to this name + while (hostResolver.Next(nameResult) == KErrNone) { + hostAdd = nameResult().iAddr; + hostAdd.Output(ipAddr); + + if (ipAddr.Length() > 0) { + if (nameResult().iAddr.Family() == KAfInet) { + // IPv4 - prepend + hostAddresses.prepend(QHostAddress(qt_TDesC2QString(ipAddr))); + } else { + // IPv6 - append + hostAddresses.append(QHostAddress(qt_TDesC2QString(ipAddr))); + } + } + } + + hostResolver.Close(); + + results.setAddresses(hostAddresses); return results; } QString QHostInfo::localHostName() { + // TODO - fill with code. return QString(); } QString QHostInfo::localDomainName() { + // TODO - fill with code. return QString(); } -- cgit v0.12 From 9c3967b7738b50655a7b9d6a5a0e89fdf2afc1df Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Thu, 9 Dec 2010 18:27:51 +0000 Subject: Fix some issues in symbian socket engine Reviewed-by: Markus Goetz --- src/network/socket/qsymbiansocketengine.cpp | 97 ++++++++++++++++++++++------- 1 file changed, 75 insertions(+), 22 deletions(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index b92b3bc..602df5c 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -75,6 +75,40 @@ QT_BEGIN_NAMESPACE +// Common constructs +#define Q_CHECK_VALID_SOCKETLAYER(function, returnValue) do { \ + if (!isValid()) { \ + qWarning(""#function" was called on an uninitialized socket device"); \ + return returnValue; \ + } } while (0) +#define Q_CHECK_INVALID_SOCKETLAYER(function, returnValue) do { \ + if (isValid()) { \ + qWarning(""#function" was called on an already initialized socket device"); \ + return returnValue; \ + } } while (0) +#define Q_CHECK_STATE(function, checkState, returnValue) do { \ + if (d->socketState != (checkState)) { \ + qWarning(""#function" was not called in "#checkState); \ + return (returnValue); \ + } } while (0) +#define Q_CHECK_NOT_STATE(function, checkState, returnValue) do { \ + if (d->socketState == (checkState)) { \ + qWarning(""#function" was called in "#checkState); \ + return (returnValue); \ + } } while (0) +#define Q_CHECK_STATES(function, state1, state2, returnValue) do { \ + if (d->socketState != (state1) && d->socketState != (state2)) { \ + qWarning(""#function" was called" \ + " not in "#state1" or "#state2); \ + return (returnValue); \ + } } while (0) +#define Q_CHECK_TYPE(function, type, returnValue) do { \ + if (d->socketType != (type)) { \ + qWarning(#function" was called by a" \ + " socket other than "#type""); \ + return (returnValue); \ + } } while (0) + #if defined QNATIVESOCKETENGINE_DEBUG /* @@ -307,7 +341,7 @@ bool QSymbianSocketEngine::initialize(int socketDescriptor, QAbstractSocket::Soc if (isValid()) close(); - if(!QSymbianSocketManager::instance().lookupSocket(socketDescriptor, d->nativeSocket)) { + if (!QSymbianSocketManager::instance().lookupSocket(socketDescriptor, d->nativeSocket)) { d->setError(QAbstractSocket::SocketResourceError, QSymbianSocketEnginePrivate::InvalidSocketErrorString); return false; @@ -539,12 +573,16 @@ bool QSymbianSocketEngine::connectToHost(const QHostAddress &addr, quint16 port) TInt err = status.Int(); if (err) { switch (err) { + case KErrWouldBlock: + d->socketState = QAbstractSocket::ConnectingState; + break; case KErrCouldNotConnect: d->setError(QAbstractSocket::ConnectionRefusedError, d->ConnectionRefusedErrorString); d->socketState = QAbstractSocket::UnconnectedState; break; case KErrTimedOut: d->setError(QAbstractSocket::NetworkError, d->ConnectionTimeOutErrorString); + d->socketState = QAbstractSocket::UnconnectedState; break; case KErrHostUnreach: d->setError(QAbstractSocket::NetworkError, d->HostUnreachableErrorString); @@ -563,8 +601,8 @@ bool QSymbianSocketEngine::connectToHost(const QHostAddress &addr, quint16 port) break; case KErrNotSupported: case KErrBadDescriptor: - d->socketState = QAbstractSocket::UnconnectedState; default: + d->socketState = QAbstractSocket::UnconnectedState; break; } @@ -592,25 +630,20 @@ bool QSymbianSocketEngine::connectToHost(const QHostAddress &addr, quint16 port) bool QSymbianSocketEngine::bind(const QHostAddress &address, quint16 port) { Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::bind(), false); + + if (!d->checkProxy(address)) + return false; + + Q_CHECK_STATE(QNativeSocketEngine::bind(), QAbstractSocket::UnconnectedState, false); + TInetAddr nativeAddr; d->setPortAndAddress(nativeAddr, port, address); TInt err = d->nativeSocket.Bind(nativeAddr); if (err) { - switch(errno) { - case KErrInUse: - d->setError(QAbstractSocket::AddressInUseError, d->AddressInuseErrorString); - break; - case KErrPermissionDenied: - d->setError(QAbstractSocket::SocketAccessError, d->AddressProtectedErrorString); - break; - case KErrNotSupported: - d->setError(QAbstractSocket::UnsupportedSocketOperationError, d->OperationUnsupportedErrorString); - break; - default: - break; - } + d->setError(err); #if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QSymbianSocketEnginePrivate::nativeBind(%s, %i) == false (%s)", @@ -625,6 +658,8 @@ bool QSymbianSocketEngine::bind(const QHostAddress &address, quint16 port) address.toString().toLatin1().constData(), port); #endif d->socketState = QAbstractSocket::BoundState; + + d->fetchConnectionParameters(); return true; } @@ -708,9 +743,7 @@ qint64 QSymbianSocketEngine::pendingDatagramSize() const Q_D(const QSymbianSocketEngine); int nbytes; TInt err = d->nativeSocket.GetOpt(KSOReadBytesPending,KSOLSocket, nbytes); - return qint64(nbytes-28); //TODO: why -28 (open C version had this)? - // Why = Could it be that this is about header lengths etc? if yes - // this could be pretty broken, especially for IPv6 + return qint64(nbytes); } @@ -853,6 +886,8 @@ bool QSymbianSocketEnginePrivate::fetchConnectionParameters() void QSymbianSocketEngine::close() { + if (!isValid()) + return; Q_D(QSymbianSocketEngine); #if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QSymbianSocketEnginePrivate::nativeClose()"); @@ -864,12 +899,18 @@ void QSymbianSocketEngine::close() d->writeNotifier->setEnabled(false); if (d->exceptNotifier) d->exceptNotifier->setEnabled(false); - if(d->asyncSelect) { + if (d->asyncSelect) { d->asyncSelect->deleteLater(); d->asyncSelect = 0; } //TODO: call nativeSocket.Shutdown(EImmediate) in some cases? + if (d->socketType == QAbstractSocket::UdpSocket) { + //TODO: Close hangs without this, but only for UDP - why? + TRequestStatus stat; + d->nativeSocket.Shutdown(RSocket::EImmediate, stat); + User::WaitForRequest(stat); + } d->nativeSocket.Close(); QSymbianSocketManager::instance().removeSocket(d->nativeSocket); d->socketDescriptor = -1; @@ -1221,8 +1262,7 @@ void QSymbianSocketEnginePrivate::setError(QAbstractSocket::SocketError error, E //TODO: use QSystemError class when file engine is merged to master void QSymbianSocketEnginePrivate::setError(TInt symbianError) { - hasSetSocketError = true; - switch(symbianError) { + switch (symbianError) { case KErrDisconnected: case KErrEof: setError(QAbstractSocket::RemoteHostClosedError, @@ -1240,12 +1280,21 @@ void QSymbianSocketEnginePrivate::setError(TInt symbianError) setError(QAbstractSocket::NetworkError, QSymbianSocketEnginePrivate::ProtocolUnsupportedErrorString); break; + case KErrInUse: + setError(QAbstractSocket::AddressInUseError, AddressInuseErrorString); + break; + case KErrPermissionDenied: + setError(QAbstractSocket::SocketAccessError, AddressProtectedErrorString); + break; + case KErrNotSupported: + setError(QAbstractSocket::UnsupportedSocketOperationError, OperationUnsupportedErrorString); + break; default: socketError = QAbstractSocket::NetworkError; socketErrorString = QString::number(symbianError); break; } - + hasSetSocketError = true; } class QReadNotifier : public QSocketNotifier @@ -1516,6 +1565,10 @@ void QAsyncSelect::RunL() iExcN->event(&e); } m_inSocketEvent = false; + if (m_deleteLater) { + delete this; + return; + } // select again (unless disabled by one of the callbacks) IssueRequest(); } -- cgit v0.12 From cb7a89049f1e41edf02aaab56a00cef8c6005eba Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 10 Dec 2010 10:27:32 +0000 Subject: Fixes for socket engine autotest failures Reviewed-by: Markus Goetz --- src/corelib/kernel/qcore_symbian_p.cpp | 2 +- src/network/socket/qsymbiansocketengine.cpp | 10 ++++++++-- src/network/socket/qsymbiansocketengine_p.h | 4 ++-- .../platformsocketengine/platformsocketengine.pro | 7 +++++-- .../platformsocketengine/tst_platformsocketengine.cpp | 19 ++++++++++++++++--- 5 files changed, 32 insertions(+), 10 deletions(-) diff --git a/src/corelib/kernel/qcore_symbian_p.cpp b/src/corelib/kernel/qcore_symbian_p.cpp index ede8464..fdae31b 100644 --- a/src/corelib/kernel/qcore_symbian_p.cpp +++ b/src/corelib/kernel/qcore_symbian_p.cpp @@ -283,7 +283,7 @@ int QSymbianSocketManager::lookupSocket(const RSocket& socket) const { bool QSymbianSocketManager::lookupSocket(int fd, RSocket& socket) const { QMutexLocker l(&iMutex); - int id = fd + socket_offset; + int id = fd - socket_offset; if(!reverseSocketMap.contains(id)) return false; socket = reverseSocketMap.value(id); diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index 602df5c..b63dbf6 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -641,6 +641,10 @@ bool QSymbianSocketEngine::bind(const QHostAddress &address, quint16 port) d->setPortAndAddress(nativeAddr, port, address); TInt err = d->nativeSocket.Bind(nativeAddr); +#ifdef __WINS__ + if (err == KErrArgument) // winsock prt returns wrong error code + err = KErrInUse; +#endif if (err) { d->setError(err); @@ -781,6 +785,8 @@ qint64 QSymbianSocketEngine::writeDatagram(const char *data, qint64 len, const QHostAddress &host, quint16 port) { Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::writeDatagram(), -1); + Q_CHECK_TYPE(QNativeSocketEngine::writeDatagram(), QAbstractSocket::UdpSocket, -1); TPtrC8 buffer((TUint8*)data, (int)len); TInetAddr addr; d->setPortAndAddress(addr, port, host); @@ -940,9 +946,9 @@ qint64 QSymbianSocketEngine::write(const char *data, qint64 len) Q_D(QSymbianSocketEngine); TPtrC8 buffer((TUint8*)data, (int)len); TSockXfrLength sentBytes = 0; - TRequestStatus status; //TODO: OMG sync send! + TRequestStatus status; d->nativeSocket.Send(buffer, 0, status, sentBytes); - User::WaitForRequest(status); + User::WaitForRequest(status); //TODO: on emulator this blocks for write >16kB (non blocking IO not implemented properly?) TInt err = status.Int(); if (err) { diff --git a/src/network/socket/qsymbiansocketengine_p.h b/src/network/socket/qsymbiansocketengine_p.h index 2d5bcd8..bc85f9c 100644 --- a/src/network/socket/qsymbiansocketengine_p.h +++ b/src/network/socket/qsymbiansocketengine_p.h @@ -172,8 +172,8 @@ private: QReadNotifier* iReadN; QWriteNotifier* iWriteN; QExceptionNotifier* iExcN; - bool m_inSocketEvent; // TODO ? - bool m_deleteLater; // TODO ? + bool m_inSocketEvent; + bool m_deleteLater; RSocket &m_socket; TUint m_selectFlags; diff --git a/tests/auto/platformsocketengine/platformsocketengine.pro b/tests/auto/platformsocketengine/platformsocketengine.pro index 04816af..faf745c 100644 --- a/tests/auto/platformsocketengine/platformsocketengine.pro +++ b/tests/auto/platformsocketengine/platformsocketengine.pro @@ -9,5 +9,8 @@ MOC_DIR=tmp QT = core network -symbian: TARGET.CAPABILITY = NetworkServices -symbian: INCLUDEPATH += $$OS_LAYER_SYSTEMINCLUDE \ No newline at end of file +symbian { + TARGET.CAPABILITY = NetworkServices + INCLUDEPATH += $$OS_LAYER_SYSTEMINCLUDE + LIBS += -lesock +} diff --git a/tests/auto/platformsocketengine/tst_platformsocketengine.cpp b/tests/auto/platformsocketengine/tst_platformsocketengine.cpp index bede360..a7b4235 100644 --- a/tests/auto/platformsocketengine/tst_platformsocketengine.cpp +++ b/tests/auto/platformsocketengine/tst_platformsocketengine.cpp @@ -65,6 +65,7 @@ #ifdef Q_OS_SYMBIAN #define PLATFORMSOCKETENGINE QSymbianSocketEngine #include +#include #else #define PLATFORMSOCKETENGINE QNativeSocketEngine #include @@ -98,12 +99,12 @@ private slots: void udpLoopbackPerformance(); void tcpLoopbackPerformance(); void readWriteBufferSize(); - void tooManySockets(); void bind(); void networkError(); void setSocketDescriptor(); void invalidSend(); void receiveUrgentData(); + void tooManySockets(); }; tst_PlatformSocketEngine::tst_PlatformSocketEngine() @@ -179,7 +180,9 @@ void tst_PlatformSocketEngine::simpleConnectToIMAP() QVERIFY(socketDevice.read(array.data(), array.size()) == available); // Check that the greeting is what we expect it to be - QCOMPARE(array.constData(), QtNetworkSettings::expectedReplyIMAP().constData()); + //QCOMPARE(array.constData(), QtNetworkSettings::expectedReplyIMAP().constData()); + QVERIFY(array.startsWith("* OK")); + QVERIFY(array.endsWith("server ready\r\n")); // Write a logout message QByteArray array2 = "ZZZ LOGOUT\r\n"; @@ -487,7 +490,7 @@ void tst_PlatformSocketEngine::tcpLoopbackPerformance() QVERIFY(client.state() == QAbstractSocket::ConnectedState); } - // The server accepts the connectio + // The server accepts the connection int socketDescriptor = server.accept(); QVERIFY(socketDescriptor > 0); @@ -497,7 +500,11 @@ void tst_PlatformSocketEngine::tcpLoopbackPerformance() QVERIFY(serverSocket.initialize(socketDescriptor)); QVERIFY(serverSocket.state() == QAbstractSocket::ConnectedState); +#if defined (Q_OS_SYMBIAN) && defined (__WINS__) + const int messageSize = 1024 * 16; +#else const int messageSize = 1024 * 256; +#endif QByteArray message1(messageSize, '@'); QByteArray answer(messageSize, '@'); @@ -610,6 +617,12 @@ void tst_PlatformSocketEngine::networkError() #ifdef Q_OS_WIN // could use shutdown to produce different errors ::closesocket(client.socketDescriptor()); +#elif defined(Q_OS_SYMBIAN) + RSocket sock; + QVERIFY(QSymbianSocketManager::instance().lookupSocket(client.socketDescriptor(), sock)); + TRequestStatus stat; + sock.Shutdown(RSocket::EImmediate, stat); + User::WaitForRequest(stat); #else ::close(client.socketDescriptor()); #endif -- cgit v0.12 From 4d86bacafad3b12ca01c20988bf578cde7bf3dae Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 10 Dec 2010 15:18:24 +0000 Subject: Platform socket engine test fixes & update TODOs Reviewed-by: Markus Goetz --- src/network/socket/qsymbiansocketengine.cpp | 20 ++++++++++++----- .../tst_platformsocketengine.cpp | 25 ++++++++++++++++------ 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index b63dbf6..90d5265 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -188,6 +188,7 @@ bool QSymbianSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType so else err = nativeSocket.Open(socketServer, family, type, protocol); //TODO: FIXME - deprecated API, make sure we always have a connection instead + //TODO: combine error handling with setError if (err != KErrNone) { switch (err) { case KErrNotSupported: @@ -375,6 +376,12 @@ bool QSymbianSocketEngine::initialize(int socketDescriptor, QAbstractSocket::Soc close(); return false; } + + // Make sure we receive out-of-band data + if (socketType == QAbstractSocket::TcpSocket + && !setOption(ReceiveOutOfBandData, 1)) { + qWarning("QNativeSocketEngine::initialize unable to inline out-of-band data"); + } } d->socketState = socketState; @@ -566,11 +573,11 @@ bool QSymbianSocketEngine::connectToHost(const QHostAddress &addr, quint16 port) TInetAddr nativeAddr; d->setPortAndAddress(nativeAddr, port, addr); - //TODO: async connect with active object - from here to end of function is a mess TRequestStatus status; d->nativeSocket.Connect(nativeAddr, status); User::WaitForRequest(status); TInt err = status.Int(); + //TODO: combine with setError(int) if (err) { switch (err) { case KErrWouldBlock: @@ -674,7 +681,8 @@ bool QSymbianSocketEngine::listen() // for a mobile platform TInt err = d->nativeSocket.Listen(50); if (err) { - switch (errno) { + //TODO: combine with setError(int) + switch (err) { case KErrInUse: d->setError(QAbstractSocket::AddressInUseError, d->PortInuseErrorString); @@ -702,7 +710,6 @@ int QSymbianSocketEngine::accept() { Q_D(QSymbianSocketEngine); RSocket blankSocket; - //TODO: this is unbelievably broken, needs to be properly async blankSocket.Open(d->socketServer); TRequestStatus status; d->nativeSocket.Accept(blankSocket, status); @@ -717,10 +724,10 @@ int QSymbianSocketEngine::accept() qint64 QSymbianSocketEngine::bytesAvailable() const { Q_D(const QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::bytesAvailable(), -1); + Q_CHECK_NOT_STATE(QNativeSocketEngine::bytesAvailable(), QAbstractSocket::UnconnectedState, false); int nbytes = 0; qint64 available = 0; - // FIXME is this the right thing also for UDP? - // What is expected for UDP, the length for the next packet I guess? TInt err = d->nativeSocket.GetOpt(KSOReadBytesPending, KSOLSocket, nbytes); if (err) return 0; @@ -735,6 +742,9 @@ qint64 QSymbianSocketEngine::bytesAvailable() const bool QSymbianSocketEngine::hasPendingDatagrams() const { Q_D(const QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::hasPendingDatagrams(), false); + Q_CHECK_NOT_STATE(QNativeSocketEngine::hasPendingDatagrams(), QAbstractSocket::UnconnectedState, false); + Q_CHECK_TYPE(QNativeSocketEngine::hasPendingDatagrams(), QAbstractSocket::UdpSocket, false); int nbytes; TInt err = d->nativeSocket.GetOpt(KSOReadBytesPending,KSOLSocket, nbytes); return err == KErrNone && nbytes > 0; diff --git a/tests/auto/platformsocketengine/tst_platformsocketengine.cpp b/tests/auto/platformsocketengine/tst_platformsocketengine.cpp index a7b4235..2fb3724 100644 --- a/tests/auto/platformsocketengine/tst_platformsocketengine.cpp +++ b/tests/auto/platformsocketengine/tst_platformsocketengine.cpp @@ -213,9 +213,6 @@ void tst_PlatformSocketEngine::simpleConnectToIMAP() //--------------------------------------------------------------------------- void tst_PlatformSocketEngine::udpLoopbackTest() { -#ifdef SYMBIAN_WINSOCK_CONNECTIVITY - QSKIP("Not working on Emulator without WinPCAP", SkipAll); -#endif PLATFORMSOCKETENGINE udpSocket; // Initialize device #1 @@ -264,9 +261,6 @@ void tst_PlatformSocketEngine::udpLoopbackTest() //--------------------------------------------------------------------------- void tst_PlatformSocketEngine::udpIPv6LoopbackTest() { -#if defined(Q_OS_SYMBIAN) - QSKIP("Symbian: IPv6 is not yet supported", SkipAll); -#endif PLATFORMSOCKETENGINE udpSocket; // Initialize device #1 @@ -695,7 +689,18 @@ void tst_PlatformSocketEngine::receiveUrgentData() // The server sends an urgent message msg = 'Q'; +#if defined(Q_OS_SYMBIAN) + RSocket sock; + QVERIFY(QSymbianSocketManager::instance().lookupSocket(socketDescriptor, sock)); + TRequestStatus stat; + TSockXfrLength len; + sock.Send(TPtrC8((TUint8*)&msg,1), KSockWriteUrgent, stat, len); + User::WaitForRequest(stat); + QVERIFY(stat == KErrNone); + QCOMPARE(len(), 1); +#else QCOMPARE(int(::send(socketDescriptor, &msg, sizeof(msg), MSG_OOB)), 1); +#endif // The client receives the urgent message QVERIFY(client.waitForRead()); @@ -708,7 +713,15 @@ void tst_PlatformSocketEngine::receiveUrgentData() // The client sends an urgent message msg = 'T'; int clientDescriptor = client.socketDescriptor(); +#if defined(Q_OS_SYMBIAN) + QVERIFY(QSymbianSocketManager::instance().lookupSocket(clientDescriptor, sock)); + sock.Send(TPtrC8((TUint8*)&msg,1), KSockWriteUrgent, stat, len); + User::WaitForRequest(stat); + QVERIFY(stat == KErrNone); + QCOMPARE(len(), 1); +#else QCOMPARE(int(::send(clientDescriptor, &msg, sizeof(msg), MSG_OOB)), 1); +#endif // The server receives the urgent message QVERIFY(serverSocket.waitForRead()); -- cgit v0.12 From 6beb46f6e2971188c13d8b2922eaa3801a890b71 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 4 Jan 2011 13:47:12 +0000 Subject: Fix compile error --- src/network/socket/qsymbiansocketengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index 90d5265..a1ff9b9 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -378,7 +378,7 @@ bool QSymbianSocketEngine::initialize(int socketDescriptor, QAbstractSocket::Soc } // Make sure we receive out-of-band data - if (socketType == QAbstractSocket::TcpSocket + if (d->socketType == QAbstractSocket::TcpSocket && !setOption(ReceiveOutOfBandData, 1)) { qWarning("QNativeSocketEngine::initialize unable to inline out-of-band data"); } -- cgit v0.12 From 29929a3c6368f62cdb58bd7255aa6f93e8d9f2f6 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Wed, 12 Jan 2011 13:58:50 +0000 Subject: Fix non blocking connect on symbian devices The socket server returns KErrAlreadyExists rather than KErrNone when connect is called as second time after the select ioctl completes. Reviewed-by: Markus Goetz Reviewed-by: Aaron Tunney --- src/network/socket/qsymbiansocketengine.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index a1ff9b9..2f991de 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -578,7 +578,10 @@ bool QSymbianSocketEngine::connectToHost(const QHostAddress &addr, quint16 port) User::WaitForRequest(status); TInt err = status.Int(); //TODO: combine with setError(int) - if (err) { + //For non blocking connect, KErrAlreadyExists is returned from the second Connect() to indicate + //the connection is up. So treat this the same as KErrNone which would be returned from the first + //call if it wouldn't block. (e.g. winsock wrapper in the emulator ignores the nonblocking flag) + if (err && err != KErrAlreadyExists) { switch (err) { case KErrWouldBlock: d->socketState = QAbstractSocket::ConnectingState; -- cgit v0.12 From 1b3b85eca8ccb1cc793586105340980cc238eae3 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Thu, 6 Jan 2011 15:16:03 +0000 Subject: Fix KERN-EXEC 0 panic on exit when bearer is searching for WLANs The access point scanner cancels itself in the destructor. This requires the handle to be valid, but it was closed in the symbian engine destructor immediately before deleting the AP scanner. Because of the way symbian active objects work, the crashing function is only called if there was an asynchronous request in progress. So it could be missed in cases where the scan completes faster than the test case. Task-number: QTBUG-16484 Reviewed-by: Markus Goetz --- src/plugins/bearer/symbian/symbianengine.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/plugins/bearer/symbian/symbianengine.cpp b/src/plugins/bearer/symbian/symbianengine.cpp index f025d86..a370d78 100644 --- a/src/plugins/bearer/symbian/symbianengine.cpp +++ b/src/plugins/bearer/symbian/symbianengine.cpp @@ -144,6 +144,10 @@ SymbianEngine::~SymbianEngine() { Cancel(); + //The scanner may be using the connection monitor so it needs to be + //deleted first while the handle is still valid. + delete ipAccessPointsAvailabilityScanner; + iConnectionMonitor.CancelNotifications(); iConnectionMonitor.Close(); @@ -151,8 +155,6 @@ SymbianEngine::~SymbianEngine() iCmManager.Close(); #endif - delete ipAccessPointsAvailabilityScanner; - // CCommsDatabase destructor uses cleanup stack. Since QNetworkConfigurationManager // is a global static, but the time we are here, E32Main() has been exited already and // the thread's default cleanup stack has been deleted. Without this line, a -- cgit v0.12 From 47604a6de645eaabb3a673bcbedafc6d0da00137 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 17 Jan 2011 13:35:58 +0000 Subject: Add QScopedValueRollback tools class. This template allows a value to be automatically rolled back to a previous state when the class goes out of scope. This can be used to maintain a valid state when an exception is thrown. Reviewed-by: mread Reviewed-by: joao --- src/corelib/tools/qscopedvaluerollback.cpp | 84 ++++++++++++++++++++++++++++++ src/corelib/tools/qscopedvaluerollback.h | 81 ++++++++++++++++++++++++++++ src/corelib/tools/tools.pri | 7 +-- 3 files changed, 169 insertions(+), 3 deletions(-) create mode 100644 src/corelib/tools/qscopedvaluerollback.cpp create mode 100644 src/corelib/tools/qscopedvaluerollback.h diff --git a/src/corelib/tools/qscopedvaluerollback.cpp b/src/corelib/tools/qscopedvaluerollback.cpp new file mode 100644 index 0000000..8933efc --- /dev/null +++ b/src/corelib/tools/qscopedvaluerollback.cpp @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore 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 "qscopedvaluerollback.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QScopedValueRollback + \brief The QScopedValueRollback resets a variable to its previous value on destruction + \since 4.8 + \ingroup misc + + The QScopedAssignment class can be used to revert state when an + exception is thrown without needing to write try-catch blocks. + + It can also be used to manage variables that are temporarily set, + such as reentrancy guards. By using this class, the variable will + be reset whether the function is exited normally, exited early by + a return statement, or exited by an exception. + + The template can only be instantiated with a type that supports assignment. + + \sa QScopedPointer +*/ + +/*! + \fn QScopedValueRollback::QScopedValueRollback(T &var) + + Stores the previous value of var internally, for revert on destruction. +*/ + +/*! + \fn QScopedValueRollback::~QScopedValueRollback() + + Assigns the previous value to the managed variable. + This is the value at construction time, or at the last call to commit() +*/ + +/*! + \fn void QScopedValueRollback::commit() + + Updates the previous value of the managed variable to its current value. +*/ + +QT_END_NAMESPACE diff --git a/src/corelib/tools/qscopedvaluerollback.h b/src/corelib/tools/qscopedvaluerollback.h new file mode 100644 index 0000000..d344ed8 --- /dev/null +++ b/src/corelib/tools/qscopedvaluerollback.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore 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$ +** +****************************************************************************/ + +#ifndef QSCOPEDVALUEROLLBACK_H +#define QSCOPEDVALUEROLLBACK_H + +#include + +QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE +QT_MODULE(Core) + +template +class QScopedValueRollback +{ +public: + QScopedValueRollback(T &var) : + varRef(var) + { + oldValue = varRef; + } + + ~QScopedValueRollback() + { + varRef = oldValue; + } + + void commit() + { + oldValue = varRef; + } + +private: + T& varRef; + T oldValue; + + Q_DISABLE_COPY(QScopedValueRollback); +}; + +QT_END_NAMESPACE +QT_END_HEADER + +#endif // QSCOPEDVALUEROLLBACK_H diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri index 03bb32d..9d564a1 100644 --- a/src/corelib/tools/tools.pri +++ b/src/corelib/tools/tools.pri @@ -29,6 +29,9 @@ HEADERS += \ tools/qrect.h \ tools/qregexp.h \ tools/qringbuffer_p.h \ + tools/qscopedpointer.h \ + tools/qscopedpointer_p.h \ + tools/qscopedvaluerollback.h \ tools/qshareddata.h \ tools/qsharedpointer.h \ tools/qsharedpointer_impl.h \ @@ -45,9 +48,7 @@ HEADERS += \ tools/qelapsedtimer.h \ tools/qunicodetables_p.h \ tools/qvarlengtharray.h \ - tools/qvector.h \ - tools/qscopedpointer.h \ - tools/qscopedpointer_p.h + tools/qvector.h SOURCES += \ -- cgit v0.12 From b1477e557681372d2c7119d637048123f0bad120 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 17 Jan 2011 15:07:46 +0000 Subject: Add autotest for QScopedValueRollback Reviewed-by: mread --- .../qscopedvaluerollback/qscopedvaluerollback.pro | 4 + .../tst_qscopedvaluerollback.cpp | 203 +++++++++++++++++++++ 2 files changed, 207 insertions(+) create mode 100644 tests/auto/qscopedvaluerollback/qscopedvaluerollback.pro create mode 100644 tests/auto/qscopedvaluerollback/tst_qscopedvaluerollback.cpp diff --git a/tests/auto/qscopedvaluerollback/qscopedvaluerollback.pro b/tests/auto/qscopedvaluerollback/qscopedvaluerollback.pro new file mode 100644 index 0000000..f06e21b --- /dev/null +++ b/tests/auto/qscopedvaluerollback/qscopedvaluerollback.pro @@ -0,0 +1,4 @@ +load(qttest_p4) +SOURCES += tst_qscopedvaluerollback.cpp +QT -= gui +CONFIG += parallel_test diff --git a/tests/auto/qscopedvaluerollback/tst_qscopedvaluerollback.cpp b/tests/auto/qscopedvaluerollback/tst_qscopedvaluerollback.cpp new file mode 100644 index 0000000..fac5702 --- /dev/null +++ b/tests/auto/qscopedvaluerollback/tst_qscopedvaluerollback.cpp @@ -0,0 +1,203 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite 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 +#include + +/*! + \class tst_QScopedValueRollback + \internal + \since 4.8 + \brief Tests class QScopedValueRollback. + + */ +class tst_QScopedValueRollback : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void leavingScope(); + void leavingScopeAfterCommit(); + void rollbackToPreviousCommit(); + void exceptions(); + void earlyExitScope(); +private: + void earlyExitScope_helper(int exitpoint, int &member); +}; + +void tst_QScopedValueRollback::leavingScope() +{ + int i = 0; + bool b = false; + QString s("This is useful"); + + //test rollback on going out of scope + { + QScopedValueRollback ri(i); + QScopedValueRollback rb(b); + QScopedValueRollback rs(s); + QCOMPARE(b, false); + QCOMPARE(i, 0); + QCOMPARE(s, QString("This is useful")); + b = true; + i = 1; + s = "Useless"; + QCOMPARE(b, true); + QCOMPARE(i, 1); + QCOMPARE(s, QString("Useless")); + } + QCOMPARE(b, false); + QCOMPARE(i, 0); + QCOMPARE(s, QString("This is useful")); +} + +void tst_QScopedValueRollback::leavingScopeAfterCommit() +{ + int i = 0; + bool b = false; + QString s("This is useful"); + + //test rollback on going out of scope + { + QScopedValueRollback ri(i); + QScopedValueRollback rb(b); + QScopedValueRollback rs(s); + QCOMPARE(b, false); + QCOMPARE(i, 0); + QCOMPARE(s, QString("This is useful")); + b = true; + i = 1; + s = "Useless"; + QCOMPARE(b, true); + QCOMPARE(i, 1); + QCOMPARE(s, QString("Useless")); + ri.commit(); + rb.commit(); + rs.commit(); + } + QCOMPARE(b, true); + QCOMPARE(i, 1); + QCOMPARE(s, QString("Useless")); +} + +void tst_QScopedValueRollback::rollbackToPreviousCommit() +{ + int i=0; + { + QScopedValueRollback ri(i); + i++; + ri.commit(); + i++; + } + QCOMPARE(i,1); + { + QScopedValueRollback ri1(i); + i++; + ri1.commit(); + i++; + ri1.commit(); + i++; + } + QCOMPARE(i,3); +} + +void tst_QScopedValueRollback::exceptions() +{ + bool b = false; + bool caught = false; + QT_TRY + { + QScopedValueRollback rb(b); + b = true; + QT_THROW(std::bad_alloc()); //if Qt compiled without exceptions this is noop + rb.commit(); //if Qt compiled without exceptions, true is committed + } + QT_CATCH(...) + { + caught = true; + } + QCOMPARE(b, !caught); //expect false if exception was thrown, true otherwise +} + +void tst_QScopedValueRollback::earlyExitScope() +{ + int i=0; + int j=0; + while (true) { + QScopedValueRollback ri(i); + i++; + j=i; + if (i>8) break; + ri.commit(); + } + QCOMPARE(i,8); + QCOMPARE(j,9); + + for (i = 0; i < 5; i++) { + j=1; + earlyExitScope_helper(i,j); + QCOMPARE(j, 1< r(member); + member *= 2; + if (exitpoint == 0) + return; + r.commit(); + member *= 2; + if (exitpoint == 1) + return; + r.commit(); + member *= 2; + if (exitpoint == 2) + return; + r.commit(); + member *= 2; + if (exitpoint == 3) + return; + r.commit(); +} + +QTEST_MAIN(tst_QScopedValueRollback) +#include "tst_QScopedValueRollback.moc" -- cgit v0.12 From 4fb5c42ede2b33c3092d70aa3e32cf6c677bd4d8 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 17 Jan 2011 15:13:52 +0000 Subject: Fix uncaught exception crash when socket ready read signal throws When the application (in this case, an autotest) ran out of memory by calling readAll() in a slot, the exception propagated to the symbian active scheduler where it caused an assertion failure. Additionally, QAbstractSocket was left in a bad state because its member variables that guard against re-entrancy were left set. 1. Catch exceptions and convert to leaves in QAsyncSelect 2. Implement RunError function to set the socket engine error state 3. Use QScopedValueRollback in QAbstractSocket to ensure the reentrancy guards are reverted if an exception is thrown. Reviewed-by: Markus Goetz Reviewed-by: mread --- src/network/socket/qabstractsocket.cpp | 10 ++++---- src/network/socket/qsymbiansocketengine.cpp | 37 +++++++++++++++++++++++++---- src/network/socket/qsymbiansocketengine_p.h | 3 +++ 3 files changed, 40 insertions(+), 10 deletions(-) diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index c638e2a..156b905 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -375,6 +375,7 @@ #include #include #include +#include #ifndef QT_NO_OPENSSL #include @@ -592,6 +593,7 @@ bool QAbstractSocketPrivate::canReadNotification() socketEngine->setReadNotificationEnabled(false); } } + QScopedValueRollback rsncrollback(readSocketNotifierCalled); readSocketNotifierCalled = true; if (!isBuffered) @@ -605,7 +607,6 @@ bool QAbstractSocketPrivate::canReadNotification() #if defined (QABSTRACTSOCKET_DEBUG) qDebug("QAbstractSocketPrivate::canReadNotification() buffer is full"); #endif - readSocketNotifierCalled = false; return false; } @@ -617,7 +618,6 @@ bool QAbstractSocketPrivate::canReadNotification() qDebug("QAbstractSocketPrivate::canReadNotification() disconnecting socket"); #endif q->disconnectFromHost(); - readSocketNotifierCalled = false; return false; } newBytes = readBuffer.size() - newBytes; @@ -637,9 +637,9 @@ bool QAbstractSocketPrivate::canReadNotification() ; if (!emittedReadyRead && hasData) { + QScopedValueRollback r(emittedReadyRead); emittedReadyRead = true; emit q->readyRead(); - emittedReadyRead = false; } // If we were closed as a result of the readyRead() signal, @@ -648,7 +648,6 @@ bool QAbstractSocketPrivate::canReadNotification() #if defined (QABSTRACTSOCKET_DEBUG) qDebug("QAbstractSocketPrivate::canReadNotification() socket is closing - returning"); #endif - readSocketNotifierCalled = false; return true; } @@ -662,7 +661,6 @@ bool QAbstractSocketPrivate::canReadNotification() socketEngine->setReadNotificationEnabled(readSocketNotifierState); readSocketNotifierStateSet = false; } - readSocketNotifierCalled = false; return true; } @@ -768,9 +766,9 @@ bool QAbstractSocketPrivate::flush() if (written > 0) { // Don't emit bytesWritten() recursively. if (!emittedBytesWritten) { + QScopedValueRollback r(emittedBytesWritten); emittedBytesWritten = true; emit q->bytesWritten(written); - emittedBytesWritten = false; } } diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index 2f991de..455bf5e 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -1308,6 +1308,9 @@ void QSymbianSocketEnginePrivate::setError(TInt symbianError) case KErrNotSupported: setError(QAbstractSocket::UnsupportedSocketOperationError, OperationUnsupportedErrorString); break; + case KErrNoMemory: + setError(QAbstractSocket::SocketResourceError, ResourceErrorString); + break; default: socketError = QAbstractSocket::NetworkError; socketErrorString = QString::number(symbianError); @@ -1564,22 +1567,47 @@ void QAsyncSelect::DoCancel() void QAsyncSelect::RunL() { + QT_TRYCATCH_LEAVING(run()); +} + +//RunError is called by the active scheduler if RunL leaves. +//Typically this will happen if a std::bad_alloc propagates down from the application +TInt QAsyncSelect::RunError(TInt aError) +{ + if (engine) { + QT_TRY { + engine->d_func()->setError(aError); + QEvent e(QEvent::SockAct); + if (iExcN) + iExcN->event(&e); + if (iReadN) + iReadN->event(&e); + } + QT_CATCH(...) {} + } +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug() << "QAsyncSelect::RunError" << aError; +#endif + return KErrNone; +} + +void QAsyncSelect::run() +{ //TODO: block when event loop demands it //if (maybeQueueForLater()) // return; - m_inSocketEvent = true; m_selectBuf() &= m_selectFlags; //the select ioctl reports everything, so mask to only what we requested //TODO: KSockSelectReadContinuation does what? - if (m_selectBuf() & KSockSelectRead) { + if (iReadN && (m_selectBuf() & KSockSelectRead)) { QEvent e(QEvent::SockAct); iReadN->event(&e); } - if (m_selectBuf() & KSockSelectWrite) { + if (iWriteN && (m_selectBuf() & KSockSelectWrite)) { QEvent e(QEvent::SockAct); iWriteN->event(&e); } - if ((m_selectBuf() & KSockSelectExcept) || iStatus != KErrNone) { + if (iExcN && ((m_selectBuf() & KSockSelectExcept) || iStatus != KErrNone)) { QEvent e(QEvent::SockAct); iExcN->event(&e); } @@ -1598,6 +1626,7 @@ void QAsyncSelect::deleteLater() iExcN = 0; iReadN = 0; iWriteN = 0; + engine = 0; m_deleteLater = true; } else { delete this; diff --git a/src/network/socket/qsymbiansocketengine_p.h b/src/network/socket/qsymbiansocketengine_p.h index bc85f9c..f36b7dd 100644 --- a/src/network/socket/qsymbiansocketengine_p.h +++ b/src/network/socket/qsymbiansocketengine_p.h @@ -72,6 +72,7 @@ class QNetworkInterface; class Q_AUTOTEST_EXPORT QSymbianSocketEngine : public QAbstractSocketEngine { Q_OBJECT + friend class QAsyncSelect; public: QSymbianSocketEngine(QObject *parent = 0); ~QSymbianSocketEngine(); @@ -167,6 +168,8 @@ public: protected: void DoCancel(); void RunL(); + void run(); + TInt RunError(TInt aError); private: QReadNotifier* iReadN; -- cgit v0.12 From 066ba528045435519917d37c781d04cea4ca4cfc Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 17 Jan 2011 19:18:39 +0000 Subject: Test case fixes for QNetworkReply 1. Increase maximum heap, as FTP large file test was running out 2. Add an additional QVERIFY so that a test fails instead of suffering an assertion failure in case no data is received. Reviewed-by: Markus Goetz --- tests/auto/qnetworkreply/test/test.pro | 2 +- tests/auto/qnetworkreply/tst_qnetworkreply.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/auto/qnetworkreply/test/test.pro b/tests/auto/qnetworkreply/test/test.pro index 7efc2fb..12fdf04 100644 --- a/tests/auto/qnetworkreply/test/test.pro +++ b/tests/auto/qnetworkreply/test/test.pro @@ -33,6 +33,6 @@ symbian:{ # Symbian toolchain does not support correct include semantics INCLUDEPATH+=..\\..\\..\\..\\include\\QtNetwork\\private # bigfile test case requires more heap - TARGET.EPOCHEAPSIZE="0x100 0x1000000" + TARGET.EPOCHEAPSIZE="0x100 0x10000000" TARGET.CAPABILITY="ALL -TCB" } diff --git a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp index c796272..b1fddfa 100644 --- a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp @@ -5128,6 +5128,7 @@ public: void finishedSlot() { // We should have already received all readyRead + QVERIFY(!bytesAvailableList.isEmpty()); QVERIFY(bytesAvailableList.last() == uploadSize); } }; -- cgit v0.12 From 4d4bc3f3729a057e428208b4037dddb49b14b1ed Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 18 Jan 2011 14:04:05 +0000 Subject: Fix some issues with socket handle allocation QAbstractSocket requires a handle of -1 to be returned when accept fails. This is a common case, as it calls accept() in a loop to get all incoming connections. Also the blank socket wasn't being closed properly on failure so that is also fixed. Fixed a possible race condition in QSymbianSocketEngine::close - the socket descriptor is now deregistered before closing the symbian socket to avoid another thread getting the symbian handle reused in open and asserting when trying to register it. This patch also adds debug around socket handle allocation when socket engine debug is enabled. Reviewed-by: Markus Goetz --- src/network/socket/qsymbiansocketengine.cpp | 35 +++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index 455bf5e..cf5f33e 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -208,8 +208,13 @@ bool QSymbianSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType so return false; } - +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug() << "QSymbianSocketEnginePrivate::createNewSocket - created" << nativeSocket.SubSessionHandle(); +#endif socketDescriptor = QSymbianSocketManager::instance().addSocket(nativeSocket); +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug() << " - allocated socket descriptor" << socketDescriptor; +#endif return true; } @@ -343,10 +348,15 @@ bool QSymbianSocketEngine::initialize(int socketDescriptor, QAbstractSocket::Soc close(); if (!QSymbianSocketManager::instance().lookupSocket(socketDescriptor, d->nativeSocket)) { + qWarning("QSymbianSocketEngine::initialize - socket descriptor not found"); d->setError(QAbstractSocket::SocketResourceError, QSymbianSocketEnginePrivate::InvalidSocketErrorString); return false; } +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug() << "QSymbianSocketEngine::initialize - attached to" << d->nativeSocket.SubSessionHandle() << socketDescriptor; +#endif + Q_ASSERT(d->socketDescriptor == socketDescriptor || d->socketDescriptor == -1); d->socketDescriptor = socketDescriptor; // determine socket type and protocol @@ -712,16 +722,28 @@ bool QSymbianSocketEngine::listen() int QSymbianSocketEngine::accept() { Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::accept(), -1); + Q_CHECK_STATE(QSymbianSocketEngine::accept(), QAbstractSocket::ListeningState, false); + Q_CHECK_TYPE(QSymbianSocketEngine::accept(), QAbstractSocket::TcpSocket, false); RSocket blankSocket; blankSocket.Open(d->socketServer); TRequestStatus status; d->nativeSocket.Accept(blankSocket, status); User::WaitForRequest(status); if (status.Int()) { + blankSocket.Close(); qWarning("QSymbianSocketEnginePrivate::nativeAccept() - error %d", status.Int()); - return 0; + return -1; } - return QSymbianSocketManager::instance().addSocket(blankSocket); + +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug() << "QSymbianSocketEnginePrivate::accept - created" << blankSocket.SubSessionHandle(); +#endif + int fd = QSymbianSocketManager::instance().addSocket(blankSocket); +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug() << " - allocated socket descriptor" << fd; +#endif + return fd; } qint64 QSymbianSocketEngine::bytesAvailable() const @@ -930,8 +952,13 @@ void QSymbianSocketEngine::close() d->nativeSocket.Shutdown(RSocket::EImmediate, stat); User::WaitForRequest(stat); } - d->nativeSocket.Close(); +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug() << "QSymbianSocketEngine::close - closing socket" << d->nativeSocket.SubSessionHandle() << d->socketDescriptor; +#endif + //remove must come before close to avoid a race where another thread gets the old subsession handle + //reused & asserts when calling QSymbianSocketManager::instance->addSocket QSymbianSocketManager::instance().removeSocket(d->nativeSocket); + d->nativeSocket.Close(); d->socketDescriptor = -1; d->socketState = QAbstractSocket::UnconnectedState; -- cgit v0.12 From 9832c60375a9689e42cd899d1de5afd0b776ae48 Mon Sep 17 00:00:00 2001 From: Aaron Tunney Date: Wed, 19 Jan 2011 16:36:46 +0000 Subject: Initial draft of QHostInfo::localHostName(), plus fix for address buffer for IPv6 addresses. Reviewed-by: Shane Kearns --- src/network/kernel/qhostinfo_symbian.cpp | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/network/kernel/qhostinfo_symbian.cpp b/src/network/kernel/qhostinfo_symbian.cpp index fbd7fe9..7fc40bc 100644 --- a/src/network/kernel/qhostinfo_symbian.cpp +++ b/src/network/kernel/qhostinfo_symbian.cpp @@ -143,7 +143,9 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) QList hostAddresses; TInetAddr hostAdd = nameResult().iAddr; - TBuf<16> ipAddr; + // 39 is the maximum length of an IPv6 address. + TBuf<39> ipAddr; + // Fill ipAddr with the IP address from hostAdd hostAdd.Output(ipAddr); if (ipAddr.Length() > 0) @@ -173,8 +175,24 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) QString QHostInfo::localHostName() { - // TODO - fill with code. - return QString(); + // Connect to ESOCK + RSocketServ socketServ(qt_symbianGetSocketServer()); + RHostResolver hostResolver; + + // Will return both IPv4 and IPv6 + // TODO: Pass RHostResolver.Open() the global RConnection + int err = hostResolver.Open(socketServ, KAfInet, KProtocolInetUdp); + if (err) + return QString(); + + THostName hostName; + err = hostResolver.GetHostName(hostName); + if (err) + return QString(); + + hostResolver.Close(); + + return qt_TDesC2QString(hostName); } QString QHostInfo::localDomainName() -- cgit v0.12 From 6886c21e0743fdfb1e5d053e0e193aeeed5fe8b2 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 21 Jan 2011 14:49:01 +0000 Subject: Fix error connecting to IPv6 addresses Incorrect usage of KAfInet6 in the symbian socket engine. KAfInet is used for both IPv4 and IPv6 as a protocol family. KAfInet6 is used as the address family for IPv6 addresses. Reviewed-by: Markus Goetz --- src/network/socket/qsymbiansocketengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index cf5f33e..9ed8a42 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -179,7 +179,7 @@ bool QSymbianSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType so QAbstractSocket::NetworkLayerProtocol socketProtocol) { Q_Q(QSymbianSocketEngine); - TUint family = (socketProtocol == QAbstractSocket::IPv6Protocol) ? KAfInet6 : KAfInet; + TUint family = KAfInet; // KAfInet6 is only used as an address family, not as a protocol family TUint type = (socketType == QAbstractSocket::UdpSocket) ? KSockDatagram : KSockStream; TUint protocol = (socketType == QAbstractSocket::UdpSocket) ? KProtocolInetUdp : KProtocolInetTcp; TInt err; -- cgit v0.12 From a2ba4ccd2c2d3daf2a4d719295c59395f03aba0b Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 21 Jan 2011 14:51:45 +0000 Subject: Fix crashes in httpProxyCommandsSynchronous test case Due to a race condition, the test could fail before its QThread had even started, resulting in a crash during thread startup. This is addressed using a semaphore to synchronise startup & ensure the sub thread is running before continuing the test. Additionally, if the test failed the QThread would be destroyed while still running, which according to the documentation will cause crashes. This is addressed using QScopedPointer to clean up when the test exits early due to failure. Reviewed-by: Markus Goetz --- tests/auto/qnetworkreply/tst_qnetworkreply.cpp | 47 +++++++++++++++++++++----- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp index b1fddfa..390d5bf 100644 --- a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -410,16 +411,23 @@ public: QTcpSocket *client; // always the last one that was received QByteArray dataToTransmit; QByteArray receivedData; + QSemaphore ready; bool doClose; bool doSsl; bool multiple; int totalConnections; - MiniHttpServer(const QByteArray &data, bool ssl = false) + MiniHttpServer(const QByteArray &data, bool ssl = false, QThread *thread = 0) : client(0), dataToTransmit(data), doClose(true), doSsl(ssl), multiple(false), totalConnections(0) { listen(); + if (thread) { + connect(thread, SIGNAL(started()), this, SLOT(threadStartedSlot())); + moveToThread(thread); + thread->start(); + ready.acquire(); + } } protected: @@ -492,6 +500,11 @@ public slots: } } } + + void threadStartedSlot() + { + ready.release(); + } }; class MyCookieJar: public QNetworkCookieJar @@ -4478,6 +4491,26 @@ void tst_QNetworkReply::httpProxyCommandsSynchronous_data() httpProxyCommands_data(); } +struct QThreadCleanup +{ + static inline void cleanup(QThread *thread) + { + thread->quit(); + if (thread->wait(3000)) + delete thread; + else + qWarning("thread hung, leaking memory so test can finish"); + } +}; + +struct QDeleteLaterCleanup +{ + static inline void cleanup(QObject *o) + { + o->deleteLater(); + } +}; + void tst_QNetworkReply::httpProxyCommandsSynchronous() { QFETCH(QUrl, url); @@ -4487,11 +4520,9 @@ void tst_QNetworkReply::httpProxyCommandsSynchronous() // when using synchronous commands, we need a different event loop for // the server thread, because the client is never returning to the // event loop - MiniHttpServer proxyServer(responseToSend); - QThread serverThread; - proxyServer.moveToThread(&serverThread); - serverThread.start(); - QNetworkProxy proxy(QNetworkProxy::HttpProxy, "127.0.0.1", proxyServer.serverPort()); + QScopedPointer serverThread(new QThread); + QScopedPointer proxyServer(new MiniHttpServer(responseToSend, false, serverThread.data())); + QNetworkProxy proxy(QNetworkProxy::HttpProxy, "127.0.0.1", proxyServer->serverPort()); manager.setProxy(proxy); QNetworkRequest request(url); @@ -4504,8 +4535,6 @@ void tst_QNetworkReply::httpProxyCommandsSynchronous() QNetworkReplyPtr reply = manager.get(request); QVERIFY(reply->isFinished()); // synchronous manager.setProxy(QNetworkProxy()); - serverThread.quit(); - serverThread.wait(3000); //qDebug() << reply->error() << reply->errorString(); @@ -4513,7 +4542,7 @@ void tst_QNetworkReply::httpProxyCommandsSynchronous() // especially since it won't succeed in the HTTPS case // so just check that the command was correct - QString receivedHeader = proxyServer.receivedData.left(expectedCommand.length()); + QString receivedHeader = proxyServer->receivedData.left(expectedCommand.length()); QCOMPARE(receivedHeader, expectedCommand); } -- cgit v0.12 From 47ac9016fc778f10f4d5ab1abb056b0d0cc2963a Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 21 Jan 2011 14:56:27 +0000 Subject: Use the global message pool to avoid KErrServerBusy errors Symbian IPC has two modes, either a preallocated message pool for the process (up to 255 allowed), or the global message pool. The default for the socket server is 8 preallocated slots, which is not enough to run the qnetworkreply autotest. However preallocating a large number of slots would be wasteful for an application that only uses one or two sockets at a time. Since we can't predict the usage, the global pool seems the best option. Reviewed-by: Iain --- src/corelib/kernel/qcore_symbian_p.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/corelib/kernel/qcore_symbian_p.cpp b/src/corelib/kernel/qcore_symbian_p.cpp index fdae31b..45e07ad 100644 --- a/src/corelib/kernel/qcore_symbian_p.cpp +++ b/src/corelib/kernel/qcore_symbian_p.cpp @@ -223,7 +223,9 @@ QSymbianSocketManager::QSymbianSocketManager() : // ### In future this could be changed to KAfInet6 when that is more common than IPv4 preferences.iAddrFamily = KAfInet; preferences.iProtocol = KProtocolInetIp; - qt_symbian_throwIfError(iSocketServ.Connect(preferences)); + //use global message pool, as we do not know how many sockets app will use + //TODO: is this the right choice? + qt_symbian_throwIfError(iSocketServ.Connect(preferences, -1)); qt_symbian_throwIfError(iSocketServ.ShareAuto()); } -- cgit v0.12 From b10fe4c9efa0767c9591fa19c86ff7e5c3f88860 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 21 Jan 2011 15:08:15 +0000 Subject: Fix IPv6 server connections Symbian treats listening on "0.0.0.0" to mean "accept any IPv4" and listening on "::" to mean "accept any IPv6". To accept any connection, you must listen with an unspecified address As the Qt documentation explicitly says QHostAddress::Any means to accept any connection, this is converted to an unspecified address (KAfUnspec) by the symbian socket engine. Reviewed-by: Markus Goetz --- src/network/socket/qsymbiansocketengine.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index 9ed8a42..cc55f2a 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -221,7 +221,12 @@ bool QSymbianSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType so void QSymbianSocketEnginePrivate::setPortAndAddress(TInetAddr& nativeAddr, quint16 port, const QHostAddress &addr) { nativeAddr.SetPort(port); - if (addr.protocol() == QAbstractSocket::IPv6Protocol) { + if (addr == QHostAddress::Any) { + //Should allow both IPv4 and IPv6 + //Listening on "0.0.0.0" accepts ONLY ipv4 connections + //Listening on "::" accepts ONLY ipv6 connections + nativeAddr.SetFamily(KAFUnspec); + } else if (addr.protocol() == QAbstractSocket::IPv6Protocol) { TPckgBuf query; query().iName = qt_QString2TPtrC(addr.scopeId()); TInt err = nativeSocket.GetOpt(KSoInetIfQueryByName, KSolInetIfQuery, query); -- cgit v0.12 From b81b429cb43e19b2211990d0aab80e78e08d87f7 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 21 Jan 2011 15:46:01 +0000 Subject: Implement moveToThread in the symbian socket engine The active object used for socket notifications (QAsyncSelect) is thread specific, so it needs to be deleted and recreated in the new thread. Reviewed-by: Markus Goetz --- src/network/socket/qsymbiansocketengine.cpp | 44 +++++++++++++++++++++++++++-- src/network/socket/qsymbiansocketengine_p.h | 4 +++ 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index cc55f2a..487f45c 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -59,6 +59,8 @@ # include "qtcpserver.h" #endif +#include + #include #include #include @@ -1576,6 +1578,41 @@ qint64 QSymbianSocketEngine::bytesToWrite() const return 0; } +//TODO: is defining PostThreadChangeEvent as QEvent::User + 1 safe? +//TODO: would QMetaObject::invokeMethod(obj, "postThreadChangeSlot", Qt::QueuedConnection) be better? +//TODO: if QTBUG-16787 is implemented, use that instead +bool QSymbianSocketEngine::event(QEvent* ev) +{ + Q_D(QSymbianSocketEngine); + switch (ev->type()) { + case QEvent::ThreadChange: + if (d->asyncSelect) { + delete d->asyncSelect; + d->asyncSelect = 0; + QEvent *postThreadChangeEvent = new QEvent(PostThreadChangeEvent); + QCoreApplication::postEvent(this, postThreadChangeEvent); + } + return true; + case PostThreadChangeEvent: + // recreate select in new thread + d->asyncSelect = q_check_ptr(new QAsyncSelect(0, d->nativeSocket, this)); + if (d->readNotifier) { + d->asyncSelect->setReadNotifier(static_cast(d->readNotifier)); + setReadNotificationEnabled(d->readNotifier->isEnabled()); + } + if (d->writeNotifier) { + d->asyncSelect->setWriteNotifier(static_cast(d->writeNotifier)); + setReadNotificationEnabled(d->writeNotifier->isEnabled()); + } + if (d->exceptNotifier) { + d->asyncSelect->setExceptionNotifier(static_cast(d->exceptNotifier)); + setReadNotificationEnabled(d->exceptNotifier->isEnabled()); + } + return true; + } + return QAbstractSocketEngine::event(ev); +} + QAsyncSelect::QAsyncSelect(QAbstractEventDispatcher *dispatcher, RSocket& sock, QSymbianSocketEngine *parent) : CActive(CActive::EPriorityStandard), m_inSocketEvent(false), @@ -1631,11 +1668,11 @@ void QAsyncSelect::run() m_inSocketEvent = true; m_selectBuf() &= m_selectFlags; //the select ioctl reports everything, so mask to only what we requested //TODO: KSockSelectReadContinuation does what? - if (iReadN && (m_selectBuf() & KSockSelectRead)) { + if (iReadN && ((m_selectBuf() & KSockSelectRead) || iStatus != KErrNone)) { QEvent e(QEvent::SockAct); iReadN->event(&e); } - if (iWriteN && (m_selectBuf() & KSockSelectWrite)) { + if (iWriteN && ((m_selectBuf() & KSockSelectWrite) || iStatus != KErrNone)) { QEvent e(QEvent::SockAct); iWriteN->event(&e); } @@ -1681,7 +1718,8 @@ void QAsyncSelect::IssueRequest() m_selectFlags = selectFlags; } if (m_selectFlags && !IsActive()) { - m_selectBuf() = m_selectFlags; + //always request errors (write notification does not complete on connect errors) + m_selectBuf() = m_selectFlags | KSockSelectExcept; m_socket.Ioctl(KIOctlSelect, iStatus, &m_selectBuf, KSOLSocket); SetActive(); } diff --git a/src/network/socket/qsymbiansocketengine_p.h b/src/network/socket/qsymbiansocketengine_p.h index f36b7dd..8a0b8df 100644 --- a/src/network/socket/qsymbiansocketengine_p.h +++ b/src/network/socket/qsymbiansocketengine_p.h @@ -135,6 +135,10 @@ public: bool isExceptionNotificationEnabled() const; void setExceptionNotificationEnabled(bool enable); + bool event(QEvent* ev); + + static const QEvent::Type PostThreadChangeEvent = (QEvent::Type)(QEvent::User + 1); + public Q_SLOTS: // TODO: Why do we do this? This is private Qt implementation stuff anyway, no need for it // non-virtual override; -- cgit v0.12 From 640152ac8057f026451da814419511cf04446eca Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 24 Jan 2011 11:58:33 +0000 Subject: Fix deprecated cast from ascii warning Reviewed-by: Aaron Tunney --- src/network/kernel/qhostinfo_symbian.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/kernel/qhostinfo_symbian.cpp b/src/network/kernel/qhostinfo_symbian.cpp index 7fc40bc..9599274 100644 --- a/src/network/kernel/qhostinfo_symbian.cpp +++ b/src/network/kernel/qhostinfo_symbian.cpp @@ -126,7 +126,7 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) // the IPv6 addresses at the end of the address list in results. // Synchronous request. - err = hostResolver.GetByName(qt_QString2TPtrC(aceHostname), nameResult); + err = hostResolver.GetByName(qt_QString2TPtrC(QString::fromLatin1(aceHostname)), nameResult); if (err) { // TODO - Could there be other errors? Symbian docs don't say. if (err = KErrNotFound) { -- cgit v0.12 From 5f41f2b4bbe3f4d3f7e2ccb6c14273c5a308b837 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 25 Jan 2011 10:43:45 +0000 Subject: qnetworkreply test stability on symbian The first few tests could randomly timeout due to delays in starting the WLAN connection. This is addressed by opening the default bearer in initTestCase, and closing it in cleanupTestCase. This will keep the connection active for the duration of the test, instead of activating/deactivating continuously. The first SSL test could randomly timeout due to the delay in fetching the CA certificates from the system (which can be very slow on some phones / SIM cards). This is addressed by preloading them in initTestCase - all the tests will then get system SSL certs from the cache. Reviewed-by: Markus Goetz --- tests/auto/qnetworkreply/tst_qnetworkreply.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp index 390d5bf..3e07176 100644 --- a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp @@ -65,6 +65,11 @@ #include #include #endif +#ifndef QT_NO_BEARERMANAGEMENT +#include +#include +#include +#endif #include @@ -136,6 +141,11 @@ class tst_QNetworkReply: public QObject QSslConfiguration storedSslConfiguration; QList storedExpectedSslErrors; #endif +#ifndef QT_NO_BEARER_MANAGEMENT + QNetworkConfigurationManager *netConfMan; + QNetworkConfiguration networkConfiguration; + QScopedPointer networkSession; +#endif public: tst_QNetworkReply(); @@ -1140,6 +1150,18 @@ void tst_QNetworkReply::initTestCase() #endif QDir::setSearchPaths("srcdir", QStringList() << SRCDIR); +#ifndef QT_NO_OPENSSL + QSslSocket::defaultCaCertificates(); //preload certificates +#endif +#ifndef QT_NO_BEARERMANAGEMENT + netConfMan = new QNetworkConfigurationManager(this); + networkConfiguration = netConfMan->defaultConfiguration(); + networkSession.reset(new QNetworkSession(networkConfiguration)); + if (!networkSession->isOpen()) { + networkSession->open(); + QVERIFY(networkSession->waitForOpened(30000)); + } +#endif } void tst_QNetworkReply::cleanupTestCase() @@ -1147,6 +1169,9 @@ void tst_QNetworkReply::cleanupTestCase() #if !defined Q_OS_WIN QFile::remove(wronlyFileName); #endif + if (networkSession && networkSession->isOpen()) { + networkSession->close(); + } } void tst_QNetworkReply::init() -- cgit v0.12 From 00553adc2ab5c38f1870b036d4bec881acb77511 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 25 Jan 2011 13:18:23 +0000 Subject: Fix some qnetworkreply test cases for symbian The unreachable IP test needs a longer timeout than on desktops. The manual construction of a file:// URL was incorrect in the case where SRCDIR is "." - this is changed to the recommended QUrl::fromLocalFile API. Reviewed-by: Markus Goetz --- tests/auto/qnetworkreply/tst_qnetworkreply.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp index 3e07176..71a8352 100644 --- a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp @@ -5302,7 +5302,7 @@ void tst_QNetworkReply::getFromUnreachableIp() QNetworkReplyPtr reply = manager.get(request); connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); - QTestEventLoop::instance().enterLoop(5); + QTestEventLoop::instance().enterLoop(10); QVERIFY(!QTestEventLoop::instance().timeout()); QVERIFY(reply->error() != QNetworkReply::NoError); @@ -5469,7 +5469,7 @@ void tst_QNetworkReply::synchronousRequest_data() << QString("text/plain"); QTest::newRow("simple-file") - << QUrl(QString::fromLatin1("file:///" SRCDIR "/rfc3252.txt")) + << QUrl::fromLocalFile(SRCDIR "/rfc3252.txt") << QString("file:" SRCDIR "/rfc3252.txt") << true << QString(); -- cgit v0.12 From b36097693f9be745e8da550ea872fd1cda8d7d3a Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 25 Jan 2011 13:30:58 +0000 Subject: Handle KErrBadName when connecting to broadcast address Symbian uses KErrBadName to indicate a badly formed socket address. It also returns this error if the address is invalid for the attempted operation, for example calling connect() with a broadcast address. Now handle this error explicitly rather than returning unknown error. Reviewed-by: Markus Goetz --- src/network/socket/qsymbiansocketengine.cpp | 7 +++++++ src/network/socket/qsymbiansocketengine_p.h | 2 ++ 2 files changed, 9 insertions(+) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index 487f45c..8ded9ac 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -626,6 +626,10 @@ bool QSymbianSocketEngine::connectToHost(const QHostAddress &addr, quint16 port) d->setError(QAbstractSocket::SocketAccessError, d->AccessErrorString); d->socketState = QAbstractSocket::UnconnectedState; break; + case KErrBadName: + d->setError(QAbstractSocket::NetworkError, d->InvalidAddressError); + d->socketState = QAbstractSocket::UnconnectedState; + break; case KErrNotSupported: case KErrBadDescriptor: default: @@ -1306,6 +1310,9 @@ void QSymbianSocketEnginePrivate::setError(QAbstractSocket::SocketError error, E case InvalidProxyTypeString: socketErrorString = QSymbianSocketEngine::tr("The proxy type is invalid for this operation"); break; + case InvalidAddressError: + socketErrorString = QSymbianSocketEngine::tr("The address is invalid for this operation"); + break; case UnknownSocketErrorString: socketErrorString = QSymbianSocketEngine::tr("Unknown error"); break; diff --git a/src/network/socket/qsymbiansocketengine_p.h b/src/network/socket/qsymbiansocketengine_p.h index 8a0b8df..fb64dba 100644 --- a/src/network/socket/qsymbiansocketengine_p.h +++ b/src/network/socket/qsymbiansocketengine_p.h @@ -233,6 +233,8 @@ public: PortInuseErrorString, NotSocketErrorString, InvalidProxyTypeString, + //symbian specific + InvalidAddressError, UnknownSocketErrorString = -1 }; -- cgit v0.12 From 54692812331d24939a0263a1625702670503c17a Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 25 Jan 2011 13:37:45 +0000 Subject: Suppress warning for an expected error QTcpServer calls accept repeatedly until it fails. So the KErrWouldBlock is an expected error - ignore this so warnings are only emitted for unexpected errors. Reviewed-by: Markus Goetz --- src/network/socket/qsymbiansocketengine.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index 8ded9ac..bee034e 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -743,7 +743,8 @@ int QSymbianSocketEngine::accept() User::WaitForRequest(status); if (status.Int()) { blankSocket.Close(); - qWarning("QSymbianSocketEnginePrivate::nativeAccept() - error %d", status.Int()); + if (status != KErrWouldBlock) + qWarning("QSymbianSocketEnginePrivate::nativeAccept() - error %d", status.Int()); return -1; } -- cgit v0.12 From cdc4ce0acde93b23c7e4941b5c195a8d23ff6900 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Wed, 5 Jan 2011 11:07:56 +0000 Subject: Workaround crash when multiple QNetworkAccessManager instances are used Instead of each QNetworkAccessManager owning a QNetworkSession, they now share a QNetworkSession if they have the same QNetworkConfiguration. QNetworkAccessManager now uses passive roaming instead of application level roaming. The state change signal (entering connected state) is used to indicate reconnection instead of being triggered when sending an ALR accept(). This preserves the previous behaviour, as QNAM always accepted the suggested access point from bearer mobility. In the case of multithreaded applications, one QNetworkSession will be created for each thread which uses QNetworkAccessManager, as QNetworkSession is not thread safe. Task-number: QT-4378 Reviewed-by: Markus Goetz Reviewed-by: juhvu --- src/network/access/qnetworkaccessmanager.cpp | 42 +++---------- src/network/access/qnetworkaccessmanager.h | 2 - src/network/access/qnetworkaccessmanager_p.h | 2 +- src/network/access/qnetworkreplyimpl.cpp | 6 +- src/network/bearer/bearer.pri | 6 +- src/network/bearer/qsharednetworksession.cpp | 90 ++++++++++++++++++++++++++++ src/network/bearer/qsharednetworksession_p.h | 81 +++++++++++++++++++++++++ 7 files changed, 188 insertions(+), 41 deletions(-) create mode 100644 src/network/bearer/qsharednetworksession.cpp create mode 100644 src/network/bearer/qsharednetworksession_p.h diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index bec217b..94ce3bc 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -48,6 +48,7 @@ #include "qabstractnetworkcache.h" #include "QtNetwork/qnetworksession.h" +#include "qsharednetworksession_p.h" #include "qnetworkaccesshttpbackend_p.h" #include "qnetworkaccessftpbackend_p.h" @@ -1343,11 +1344,8 @@ void QNetworkAccessManagerPrivate::createSession(const QNetworkConfiguration &co initializeSession = false; - if (networkSession) - delete networkSession; - if (!config.isValid()) { - networkSession = 0; + networkSession.clear(); online = false; if (networkAccessible == QNetworkAccessManager::NotAccessible) @@ -1358,18 +1356,12 @@ void QNetworkAccessManagerPrivate::createSession(const QNetworkConfiguration &co return; } - networkSession = new QNetworkSession(config, q); + networkSession = QSharedNetworkSessionManager::getSession(config); - QObject::connect(networkSession, SIGNAL(opened()), q, SIGNAL(networkSessionConnected())); - QObject::connect(networkSession, SIGNAL(closed()), q, SLOT(_q_networkSessionClosed())); - QObject::connect(networkSession, SIGNAL(stateChanged(QNetworkSession::State)), + QObject::connect(networkSession.data(), SIGNAL(opened()), q, SIGNAL(networkSessionConnected())); + QObject::connect(networkSession.data(), SIGNAL(closed()), q, SLOT(_q_networkSessionClosed())); + QObject::connect(networkSession.data(), SIGNAL(stateChanged(QNetworkSession::State)), q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State))); - QObject::connect(networkSession, SIGNAL(newConfigurationActivated()), - q, SLOT(_q_networkSessionNewConfigurationActivated())); - QObject::connect(networkSession, - SIGNAL(preferredConfigurationChanged(QNetworkConfiguration,bool)), - q, - SLOT(_q_networkSessionPreferredConfigurationChanged(QNetworkConfiguration,bool))); _q_networkSessionStateChanged(networkSession->state()); } @@ -1379,32 +1371,16 @@ void QNetworkAccessManagerPrivate::_q_networkSessionClosed() if (networkSession) { networkConfiguration = networkSession->configuration().identifier(); - networkSession->deleteLater(); - networkSession = 0; - } -} - -void QNetworkAccessManagerPrivate::_q_networkSessionNewConfigurationActivated() -{ - Q_Q(QNetworkAccessManager); - - if (networkSession) { - networkSession->accept(); - - emit q->networkSessionConnected(); + networkSession.clear(); } } -void QNetworkAccessManagerPrivate::_q_networkSessionPreferredConfigurationChanged(const QNetworkConfiguration &, bool) -{ - if (networkSession) - networkSession->migrate(); -} - void QNetworkAccessManagerPrivate::_q_networkSessionStateChanged(QNetworkSession::State state) { Q_Q(QNetworkAccessManager); + if (state == QNetworkSession::Connected) + emit q->networkSessionConnected(); if (online) { if (state != QNetworkSession::Connected && state != QNetworkSession::Roaming) { online = false; diff --git a/src/network/access/qnetworkaccessmanager.h b/src/network/access/qnetworkaccessmanager.h index 95e45f0..9c551a7 100644 --- a/src/network/access/qnetworkaccessmanager.h +++ b/src/network/access/qnetworkaccessmanager.h @@ -161,8 +161,6 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_replySslErrors(QList)) #if !defined(QT_NO_BEARERMANAGEMENT) && !defined(QT_MOBILITY_BEARER) Q_PRIVATE_SLOT(d_func(), void _q_networkSessionClosed()) - Q_PRIVATE_SLOT(d_func(), void _q_networkSessionNewConfigurationActivated()) - Q_PRIVATE_SLOT(d_func(), void _q_networkSessionPreferredConfigurationChanged(QNetworkConfiguration,bool)) Q_PRIVATE_SLOT(d_func(), void _q_networkSessionStateChanged(QNetworkSession::State)) #endif }; diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h index 2c6ee10..cdc4b3d 100644 --- a/src/network/access/qnetworkaccessmanager_p.h +++ b/src/network/access/qnetworkaccessmanager_p.h @@ -128,7 +128,7 @@ public: #endif #ifndef QT_NO_BEARERMANAGEMENT - QNetworkSession *networkSession; + QSharedPointer networkSession; QString networkConfiguration; QNetworkAccessManager::NetworkAccessibility networkAccessible; bool online; diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp index 70c318c..373cb22 100644 --- a/src/network/access/qnetworkreplyimpl.cpp +++ b/src/network/access/qnetworkreplyimpl.cpp @@ -97,7 +97,7 @@ void QNetworkReplyImplPrivate::_q_startOperation() // state changes. state = WaitingForSession; - QNetworkSession *session = manager->d_func()->networkSession; + QNetworkSession *session = manager->d_func()->networkSession.data(); if (session) { Q_Q(QNetworkReplyImpl); @@ -257,7 +257,7 @@ void QNetworkReplyImplPrivate::_q_networkSessionConnected() if (manager.isNull()) return; - QNetworkSession *session = manager->d_func()->networkSession; + QNetworkSession *session = manager->d_func()->networkSession.data(); if (!session) return; @@ -693,7 +693,7 @@ void QNetworkReplyImplPrivate::finished() if (!manager.isNull()) { #ifndef QT_NO_BEARERMANAGEMENT - QNetworkSession *session = manager->d_func()->networkSession; + QNetworkSession *session = manager->d_func()->networkSession.data(); if (session && session->state() == QNetworkSession::Roaming && state == Working && errorCode != QNetworkReply::OperationCanceledError) { // only content with a known size will fail with a temporary network failure error diff --git a/src/network/bearer/bearer.pri b/src/network/bearer/bearer.pri index bc5b0b5..d58d5ec 100644 --- a/src/network/bearer/bearer.pri +++ b/src/network/bearer/bearer.pri @@ -7,11 +7,13 @@ HEADERS += bearer/qnetworkconfiguration.h \ bearer/qnetworkconfiguration_p.h \ bearer/qnetworksession_p.h \ bearer/qbearerengine_p.h \ - bearer/qbearerplugin_p.h + bearer/qbearerplugin_p.h \ + bearer/qsharednetworksession_p.h SOURCES += bearer/qnetworksession.cpp \ bearer/qnetworkconfigmanager.cpp \ bearer/qnetworkconfiguration.cpp \ bearer/qnetworkconfigmanager_p.cpp \ bearer/qbearerengine.cpp \ - bearer/qbearerplugin.cpp + bearer/qbearerplugin.cpp \ + bearer/qsharednetworksession.cpp diff --git a/src/network/bearer/qsharednetworksession.cpp b/src/network/bearer/qsharednetworksession.cpp new file mode 100644 index 0000000..51b3a32 --- /dev/null +++ b/src/network/bearer/qsharednetworksession.cpp @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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 "qsharednetworksession_p.h" +#include "qbearerengine_p.h" +#include + +#ifndef QT_NO_BEARERMANAGEMENT + +QT_BEGIN_NAMESPACE + +QThreadStorage tls; + +inline QSharedNetworkSessionManager* sharedNetworkSessionManager() +{ + QSharedNetworkSessionManager* rv = tls.localData(); + if (!rv) { + rv = new QSharedNetworkSessionManager; + tls.setLocalData(rv); + } + return rv; +} + +QSharedPointer QSharedNetworkSessionManager::getSession(QNetworkConfiguration config) +{ + QSharedNetworkSessionManager *m(sharedNetworkSessionManager()); + //if already have a session, return it + if (m->sessions.contains(config)) { + QSharedPointer p = m->sessions.value(config).toStrongRef(); + if (!p.isNull()) + return p; + } + //otherwise make one + QSharedPointer session(new QNetworkSession(config)); + m->sessions[config] = session; + return session; +} + +void QSharedNetworkSessionManager::setSession(QNetworkConfiguration config, QSharedPointer session) +{ + QSharedNetworkSessionManager *m(sharedNetworkSessionManager()); + m->sessions[config] = session; +} + +uint qHash(const QNetworkConfiguration& config) +{ + return ((uint)config.type()) | (((uint)config.bearerType()) << 8) | (((uint)config.purpose()) << 16); +} + +QT_END_NAMESPACE + +#endif // QT_NO_BEARERMANAGEMENT diff --git a/src/network/bearer/qsharednetworksession_p.h b/src/network/bearer/qsharednetworksession_p.h new file mode 100644 index 0000000..dc84166 --- /dev/null +++ b/src/network/bearer/qsharednetworksession_p.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QSHAREDNETWORKSESSIONPRIVATE_H +#define QSHAREDNETWORKSESSIONPRIVATE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qnetworksession.h" +#include "qnetworkconfiguration.h" +#include +#include +#include +#include + +#ifndef QT_NO_BEARERMANAGEMENT + +QT_BEGIN_NAMESPACE + +class QSharedNetworkSessionManager +{ +public: + static QSharedPointer getSession(QNetworkConfiguration config); + static void setSession(QNetworkConfiguration config, QSharedPointer session); +private: + QHash > sessions; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_BEARERMANAGEMENT + +#endif //QSHAREDNETWORKSESSIONPRIVATE_H + -- cgit v0.12 From c546754be723c35a61a8aa5df066aa8dce053d56 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 17 Jan 2011 12:44:06 +0000 Subject: Fix header not found build error Task-Number: QT-4378 --- src/network/access/qnetworkaccessmanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 94ce3bc..7d37375 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -48,7 +48,7 @@ #include "qabstractnetworkcache.h" #include "QtNetwork/qnetworksession.h" -#include "qsharednetworksession_p.h" +#include "QtNetwork/private/qsharednetworksession_p.h" #include "qnetworkaccesshttpbackend_p.h" #include "qnetworkaccessftpbackend_p.h" -- cgit v0.12 From 07416116e30ec526506c6f2c97be4499b898dda0 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Thu, 27 Jan 2011 14:28:46 +0000 Subject: Fix for QNetworkSession::waitForOpened failing on active connection When opening an active session, waitForOpened was failing because the state was Connected rather than Connecting. This is fixed to allow Connected as a state. Reviewed-by: Markus Goetz --- src/network/bearer/qnetworksession.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/bearer/qnetworksession.cpp b/src/network/bearer/qnetworksession.cpp index eac0456..41a8854 100644 --- a/src/network/bearer/qnetworksession.cpp +++ b/src/network/bearer/qnetworksession.cpp @@ -310,7 +310,7 @@ bool QNetworkSession::waitForOpened(int msecs) if (d->isOpen) return true; - if (d->state != Connecting) + if (d->state != Connecting && d->state != Connected) //state is connected when opening an already active interface return false; QEventLoop loop; -- cgit v0.12 From 85ee65df53ddece16b9d51fae0de1dd36564564a Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 28 Jan 2011 17:38:56 +0000 Subject: Fix compile errors when TCP local sockets configured on symbian Reviewed-by: Markus Goetz --- src/network/socket/qlocalserver.cpp | 2 +- src/network/socket/qlocalsocket.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/network/socket/qlocalserver.cpp b/src/network/socket/qlocalserver.cpp index ef7fc02..6d8b889 100644 --- a/src/network/socket/qlocalserver.cpp +++ b/src/network/socket/qlocalserver.cpp @@ -274,11 +274,11 @@ QLocalSocket *QLocalServer::nextPendingConnection() if (d->pendingConnections.isEmpty()) return 0; QLocalSocket *nextSocket = d->pendingConnections.dequeue(); +#ifndef QT_LOCALSOCKET_TCP #ifdef Q_OS_SYMBIAN if(!d->socketNotifier) return nextSocket; #endif -#ifndef QT_LOCALSOCKET_TCP if (d->pendingConnections.size() <= d->maxPendingConnections) #ifndef Q_OS_WIN d->socketNotifier->setEnabled(true); diff --git a/src/network/socket/qlocalsocket.cpp b/src/network/socket/qlocalsocket.cpp index 2eb1700..aa11d05 100644 --- a/src/network/socket/qlocalsocket.cpp +++ b/src/network/socket/qlocalsocket.cpp @@ -346,7 +346,7 @@ QLocalSocket::QLocalSocket(QObject * parent) QLocalSocket::~QLocalSocket() { close(); -#ifndef Q_OS_WIN +#if !defined (Q_OS_WIN) && !defined (QT_LOCALSOCKET_TCP) Q_D(QLocalSocket); d->unixSocket.setParent(0); #endif -- cgit v0.12 From 2ff5c6adbca65405d0a760173e5128b98d5d4a40 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 28 Jan 2011 17:39:57 +0000 Subject: Enable QT_LOCALSOCKET_TCP for symbian Reviewed-by: Markus Goetz --- src/network/socket/socket.pri | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/network/socket/socket.pri b/src/network/socket/socket.pri index 3eb54a2..32be429 100644 --- a/src/network/socket/socket.pri +++ b/src/network/socket/socket.pri @@ -30,11 +30,19 @@ symbian:HEADERS += socket/qsymbiansocketengine_p.h !symbian:SOURCES += socket/qnativesocketengine.cpp !symbian:HEADERS += socket/qnativesocketengine_p.h -unix:!symbian:SOURCES += socket/qnativesocketengine_unix.cpp - -unix:SOURCES += \ +unix:!symbian: { + SOURCES += socket/qnativesocketengine_unix.cpp \ socket/qlocalsocket_unix.cpp \ socket/qlocalserver_unix.cpp +} + +symbian: { + SOURCES += socket/qlocalsocket_tcp.cpp \ + socket/qlocalserver_tcp.cpp + + DEFINES += QT_LOCALSOCKET_TCP +} + unix:HEADERS += \ socket/qnet_unix_p.h -- cgit v0.12 From c8a1b65ab2491886ac37a1726b3728e549d505a7 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 28 Jan 2011 18:45:15 +0000 Subject: Implement multicast functions Reviewed-by: Aaron Tunney Reviewed-by: Markus Goetz --- src/network/socket/qsymbiansocketengine.cpp | 112 ++++++++++++++++------------ src/network/socket/qsymbiansocketengine_p.h | 5 ++ 2 files changed, 69 insertions(+), 48 deletions(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index bee034e..6825374 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -436,40 +436,14 @@ bool QSymbianSocketEngine::setOption(QAbstractSocketEngine::SocketOption opt, in if (!isValid()) return false; - int n = 0; - int level = SOL_SOCKET; // default + TUint n = 0; + TUint level = KSOLSocket; // default - switch (opt) { - case QAbstractSocketEngine::ReceiveBufferSocketOption: - n = KSORecvBuf; - break; - case QAbstractSocketEngine::SendBufferSocketOption: - n = KSOSendBuf; - break; - case QAbstractSocketEngine::BroadcastSocketOption: - return true; - case QAbstractSocketEngine::NonBlockingSocketOption: - n = KSONonBlockingIO; - break; - case QAbstractSocketEngine::AddressReusable: - level = KSolInetIp; - n = KSoReuseAddr; - break; - case QAbstractSocketEngine::BindExclusively: + if (!QSymbianSocketEnginePrivate::translateSocketOption(opt, n, level)) + return false; + + if (!level && !n) return true; - case QAbstractSocketEngine::ReceiveOutOfBandData: - level = KSolInetTcp; - n = KSoTcpOobInline; - break; - case QAbstractSocketEngine::LowDelayOption: - level = KSolInetTcp; - n = KSoTcpNoDelay; - break; - case QAbstractSocketEngine::KeepAliveOption: - level = KSolInetTcp; - n = KSoTcpKeepAlive; - break; - } return (KErrNone == d->nativeSocket.SetOpt(n, level, v)); } @@ -486,6 +460,24 @@ int QSymbianSocketEngine::option(QAbstractSocketEngine::SocketOption opt) const TUint n; TUint level = KSOLSocket; // default + if (!QSymbianSocketEnginePrivate::translateSocketOption(opt, n, level)) + return false; + + if (!level && !n) + return 1; + + int v = -1; + //GetOpt() is non const + TInt err = d->nativeSocket.GetOpt(n, level, v); + if (!err) + return v; + + return -1; +} + +bool QSymbianSocketEnginePrivate::translateSocketOption(QAbstractSocketEngine::SocketOption opt, TUint &n, TUint &level) +{ + switch (opt) { case QAbstractSocketEngine::ReceiveBufferSocketOption: n = KSORecvBuf; @@ -496,13 +488,14 @@ int QSymbianSocketEngine::option(QAbstractSocketEngine::SocketOption opt) const case QAbstractSocketEngine::NonBlockingSocketOption: n = KSONonBlockingIO; break; - case QAbstractSocketEngine::BroadcastSocketOption: - return true; //symbian doesn't support or require this option case QAbstractSocketEngine::AddressReusable: level = KSolInetIp; n = KSoReuseAddr; break; + case QAbstractSocketEngine::BroadcastSocketOption: case QAbstractSocketEngine::BindExclusively: + level = 0; + n = 0; return true; case QAbstractSocketEngine::ReceiveOutOfBandData: level = KSolInetTcp; @@ -516,17 +509,18 @@ int QSymbianSocketEngine::option(QAbstractSocketEngine::SocketOption opt) const level = KSolInetTcp; n = KSoTcpKeepAlive; break; + case QAbstractSocketEngine::MulticastLoopbackOption: + level = KSolInetIp; + n = KSoIp6MulticastLoop; + break; + case QAbstractSocketEngine::MulticastTtlOption: + level = KSolInetIp; + n = KSoIp6MulticastHops; + break; default: - return -1; + return false; } - - int v = -1; - //GetOpt() is non const - TInt err = d->nativeSocket.GetOpt(n, level, v); - if (!err) - return v; - - return -1; + return true; } qint64 QSymbianSocketEngine::receiveBufferSize() const @@ -1156,15 +1150,37 @@ int QSymbianSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool bool QSymbianSocketEngine::joinMulticastGroup(const QHostAddress &groupAddress, const QNetworkInterface &iface) { - //TODO - return false; + Q_D(QSymbianSocketEngine); + return d->multicastGroupMembershipHelper(groupAddress, iface, KSoIp6JoinGroup); } bool QSymbianSocketEngine::leaveMulticastGroup(const QHostAddress &groupAddress, const QNetworkInterface &iface) { - //TODO - return false; + Q_D(QSymbianSocketEngine); + return d->multicastGroupMembershipHelper(groupAddress, iface, KSoIp6LeaveGroup); +} + +bool QSymbianSocketEnginePrivate::multicastGroupMembershipHelper(const QHostAddress &groupAddress, + const QNetworkInterface &iface, + TUint operation) +{ + //TODO - untested + //translate address + TPckgBuf option; + Q_IPV6ADDR ip6 = groupAddress.toIPv6Address(); + memcpy(option().iAddr.u.iAddr8, ip6.c, 16); + //translate interface + //TODO - can we just use iface.index() ? + TPckgBuf query; + query().iName = qt_QString2TPtrC(iface.name()); + TInt err = nativeSocket.GetOpt(KSoInetIfQueryByName, KSolInetIfQuery, query); + if (err == KErrNone) + option().iInterface = query().iIndex; + else + option().iInterface = 0; + //join or leave group + return (KErrNone == nativeSocket.SetOpt(operation, KSolInetIp, option)); } QNetworkInterface QSymbianSocketEngine::multicastInterface() const @@ -1175,7 +1191,7 @@ QNetworkInterface QSymbianSocketEngine::multicastInterface() const bool QSymbianSocketEngine::setMulticastInterface(const QNetworkInterface &iface) { - //TODO + //TODO - this is possibly a unix'ism as the RConnection on which the socket was created is probably controlling this return false; } diff --git a/src/network/socket/qsymbiansocketengine_p.h b/src/network/socket/qsymbiansocketengine_p.h index fb64dba..df93fe6 100644 --- a/src/network/socket/qsymbiansocketengine_p.h +++ b/src/network/socket/qsymbiansocketengine_p.h @@ -254,6 +254,11 @@ public: bool checkProxy(const QHostAddress &address); bool fetchConnectionParameters(); + + bool multicastGroupMembershipHelper(const QHostAddress &groupAddress, + const QNetworkInterface &iface, + TUint operation); + static bool translateSocketOption(QAbstractSocketEngine::SocketOption opt, TUint &n, TUint &level); }; QT_END_NAMESPACE -- cgit v0.12 From c466df7e67b1af663be73fca94bb1f2951ba7371 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 31 Jan 2011 18:35:01 +0000 Subject: Fix for pendingDatagramSize() in symbian socket engine The low level socket option returns the size including IP headers, as there is an option in receive to include headers in the datagram. This is OK for a "size will not exceed" metric for buffer allocation, but Qt relies on it being an accurate size. Open C did this by subtracting 28, but that isn't valid for IPv6 which has a 40 byte header. (we can't tell whether the buffered datagram was received over IPv4 or IPv6) To fix this, do a read with the peek option set, and only care about the size. In future it would be good to not peek, but rather return this buffer to a following call to readDatagram. Reviewed-by: Aaron Tunney --- src/network/socket/qsymbiansocketengine.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index 6825374..f2c7b20 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -788,6 +788,20 @@ qint64 QSymbianSocketEngine::pendingDatagramSize() const Q_D(const QSymbianSocketEngine); int nbytes; TInt err = d->nativeSocket.GetOpt(KSOReadBytesPending,KSOLSocket, nbytes); + if (nbytes > 0) { + //nbytes includes IP header, which is of variable length (IPv4 with or without options, IPv6...) + QByteArray next(nbytes,0); + TPtr8 buffer((TUint8*)next.data(), next.size()); + TInetAddr addr; + TRequestStatus status; + //TODO: rather than peek, should we save this for next call to readDatagram? + //what if calls don't match though? + d->nativeSocket.RecvFrom(buffer, addr, KSockReadPeek, status); + User::WaitForRequest(status); + if (status.Int()) + return 0; + return buffer.Length(); + } return qint64(nbytes); } -- cgit v0.12 From f60ed3a2da4889cce6afbb059773a6c070929bb6 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 31 Jan 2011 18:50:13 +0000 Subject: Fix low level broadcast test on symbian Broadcast and multicast are optional features for network interfaces on Symbian. WLAN supports both, while IPv4 and IPv6 loopback support only multicast. The test tries to start the bearer, to get an interface that does support broadcast. There is an expect fail for the 0 bytes written case, as this is what happens on symbian if none of the interfaces support broadcast. On the phones which don't have WLAN, this is likely. Reviewed-by: Markus Goetz --- .../tst_platformsocketengine.cpp | 30 ++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/tests/auto/platformsocketengine/tst_platformsocketengine.cpp b/tests/auto/platformsocketengine/tst_platformsocketengine.cpp index 2fb3724..fa21ed8 100644 --- a/tests/auto/platformsocketengine/tst_platformsocketengine.cpp +++ b/tests/auto/platformsocketengine/tst_platformsocketengine.cpp @@ -63,6 +63,10 @@ #include #ifdef Q_OS_SYMBIAN +#include +#include +#include +#include #define PLATFORMSOCKETENGINE QSymbianSocketEngine #include #include @@ -310,6 +314,20 @@ void tst_PlatformSocketEngine::udpIPv6LoopbackTest() //--------------------------------------------------------------------------- void tst_PlatformSocketEngine::broadcastTest() { +#ifdef Q_OS_SYMBIAN + //broadcast isn't supported on loopback connections, but is on WLAN +#ifndef QT_NO_BEARERMANAGEMENT + QScopedPointer netConfMan(new QNetworkConfigurationManager()); + QNetworkConfiguration networkConfiguration(netConfMan->defaultConfiguration()); + QScopedPointer networkSession(new QNetworkSession(networkConfiguration)); + if (!networkSession->isOpen()) { + networkSession->open(); + bool ok = networkSession->waitForOpened(30000); + qDebug() << networkSession->isOpen() << networkSession->error() << networkSession->errorString(); + QVERIFY(ok); + } +#endif +#endif #ifdef Q_OS_AIX QSKIP("Broadcast does not work on darko", SkipAll); #endif @@ -327,10 +345,18 @@ void tst_PlatformSocketEngine::broadcastTest() // Broadcast an inappropriate troll message QByteArray trollMessage = "MOOT wtf is a MOOT? talk english not your sutpiD ENGLISH."; - QVERIFY(broadcastSocket.writeDatagram(trollMessage.data(), + qint64 written = broadcastSocket.writeDatagram(trollMessage.data(), trollMessage.size(), QHostAddress::Broadcast, - port) == trollMessage.size()); + port); + +#ifdef Q_OS_SYMBIAN + //On symbian, broadcasts return 0 bytes written if none of the interfaces support it. + //Notably the loopback interfaces do not. (though they do support multicast!?) + if (written == 0) + QEXPECT_FAIL("", "No active interface supports broadcast", Abort); +#endif + QCOMPARE((int)written, trollMessage.size()); // Wait until we receive it ourselves #if defined(Q_OS_FREEBSD) -- cgit v0.12 From 2a6d7fcde4092f41230841bbe4c078f2e42166bb Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 1 Feb 2011 11:18:19 +0000 Subject: Change default type for http POST to application/octet-stream When the application did not set the mandatory content-type header for POST requests, Qt was putting in application/x-www-urlencoded. While this is the default for HTML forms, it isn't valid because Qt was not also encoding the data. Reviewed-by: Markus Goetz --- src/network/access/qhttpnetworkrequest.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/network/access/qhttpnetworkrequest.cpp b/src/network/access/qhttpnetworkrequest.cpp index d2f3212..d4c735d 100644 --- a/src/network/access/qhttpnetworkrequest.cpp +++ b/src/network/access/qhttpnetworkrequest.cpp @@ -158,8 +158,10 @@ QByteArray QHttpNetworkRequestPrivate::header(const QHttpNetworkRequest &request } if (request.d->operation == QHttpNetworkRequest::Post) { // add content type, if not set in the request - if (request.headerField("content-type").isEmpty()) - ba += "Content-Type: application/x-www-form-urlencoded\r\n"; + if (request.headerField("content-type").isEmpty()) { + qWarning("content-type missing in HTTP POST, defaulting to application/octet-stream"); + ba += "Content-Type: application/octet-stream\r\n"; + } if (!request.d->uploadByteDevice && request.d->url.hasQuery()) { QByteArray query = request.d->url.encodedQuery(); ba += "Content-Length: "; -- cgit v0.12 From 2d30fce0c46fb5b98aec428869668bc345eeab8a Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 1 Feb 2011 15:52:28 +0000 Subject: Unification of error handling in symbian socket engine Reviewed-by: Markus Goetz --- src/network/socket/qsymbiansocketengine.cpp | 79 +++++++++-------------------- 1 file changed, 24 insertions(+), 55 deletions(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index f2c7b20..df0675e 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -67,6 +67,7 @@ #include #include +#include #define QNATIVESOCKETENGINE_DEBUG @@ -190,7 +191,6 @@ bool QSymbianSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType so else err = nativeSocket.Open(socketServer, family, type, protocol); //TODO: FIXME - deprecated API, make sure we always have a connection instead - //TODO: combine error handling with setError if (err != KErrNone) { switch (err) { case KErrNotSupported: @@ -198,13 +198,8 @@ bool QSymbianSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType so setError(QAbstractSocket::UnsupportedSocketOperationError, ProtocolUnsupportedErrorString); break; - case KErrNoMemory: - setError(QAbstractSocket::SocketResourceError, ResourceErrorString); - break; - case KErrPermissionDenied: - setError(QAbstractSocket::SocketAccessError, AccessErrorString); - break; default: + setError(err); break; } @@ -588,7 +583,6 @@ bool QSymbianSocketEngine::connectToHost(const QHostAddress &addr, quint16 port) d->nativeSocket.Connect(nativeAddr, status); User::WaitForRequest(status); TInt err = status.Int(); - //TODO: combine with setError(int) //For non blocking connect, KErrAlreadyExists is returned from the second Connect() to indicate //the connection is up. So treat this the same as KErrNone which would be returned from the first //call if it wouldn't block. (e.g. winsock wrapper in the emulator ignores the nonblocking flag) @@ -597,36 +591,8 @@ bool QSymbianSocketEngine::connectToHost(const QHostAddress &addr, quint16 port) case KErrWouldBlock: d->socketState = QAbstractSocket::ConnectingState; break; - case KErrCouldNotConnect: - d->setError(QAbstractSocket::ConnectionRefusedError, d->ConnectionRefusedErrorString); - d->socketState = QAbstractSocket::UnconnectedState; - break; - case KErrTimedOut: - d->setError(QAbstractSocket::NetworkError, d->ConnectionTimeOutErrorString); - d->socketState = QAbstractSocket::UnconnectedState; - break; - case KErrHostUnreach: - d->setError(QAbstractSocket::NetworkError, d->HostUnreachableErrorString); - d->socketState = QAbstractSocket::UnconnectedState; - break; - case KErrNetUnreach: - d->setError(QAbstractSocket::NetworkError, d->NetworkUnreachableErrorString); - d->socketState = QAbstractSocket::UnconnectedState; - break; - case KErrInUse: - d->setError(QAbstractSocket::NetworkError, d->AddressInuseErrorString); - break; - case KErrPermissionDenied: - d->setError(QAbstractSocket::SocketAccessError, d->AccessErrorString); - d->socketState = QAbstractSocket::UnconnectedState; - break; - case KErrBadName: - d->setError(QAbstractSocket::NetworkError, d->InvalidAddressError); - d->socketState = QAbstractSocket::UnconnectedState; - break; - case KErrNotSupported: - case KErrBadDescriptor: default: + d->setError(err); d->socketState = QAbstractSocket::UnconnectedState; break; } @@ -699,15 +665,7 @@ bool QSymbianSocketEngine::listen() // for a mobile platform TInt err = d->nativeSocket.Listen(50); if (err) { - //TODO: combine with setError(int) - switch (err) { - case KErrInUse: - d->setError(QAbstractSocket::AddressInUseError, - d->PortInuseErrorString); - break; - default: - break; - } + d->setError(err); #if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QSymbianSocketEnginePrivate::nativeListen() == false (%s)", @@ -846,9 +804,9 @@ qint64 QSymbianSocketEngine::writeDatagram(const char *data, qint64 len, TInetAddr addr; d->setPortAndAddress(addr, port, host); TSockXfrLength sentBytes; - TRequestStatus status; //TODO: OMG sync send! + TRequestStatus status; d->nativeSocket.SendTo(buffer, addr, 0, status, sentBytes); - User::WaitForRequest(status); + User::WaitForRequest(status); //Non blocking send TInt err = status.Int(); if (err) { @@ -882,8 +840,10 @@ bool QSymbianSocketEnginePrivate::fetchConnectionParameters() return false; if (!nativeSocket.SubSessionHandle()) { - if (!QSymbianSocketManager::instance().lookupSocket(socketDescriptor, nativeSocket)) + if (!QSymbianSocketManager::instance().lookupSocket(socketDescriptor, nativeSocket)) { + setError(QAbstractSocket::UnsupportedSocketOperationError, InvalidSocketErrorString); return false; + } } // Determine local address @@ -912,8 +872,8 @@ bool QSymbianSocketEnginePrivate::fetchConnectionParameters() TProtocolDesc protocol; TInt err = nativeSocket.Info(protocol); if (err) { - // ? - // QAbstractSocket::UnknownSocketType; + setError(err); + return false; } else { switch (protocol.iProtocol) { case KProtocolInetTcp: @@ -1052,9 +1012,9 @@ qint64 QSymbianSocketEngine::read(char *data, qint64 maxSize) TPtr8 buffer((TUint8*)data, (int)maxSize); TSockXfrLength received = 0; - TRequestStatus status; //TODO: OMG sync receive! + TRequestStatus status; d->nativeSocket.RecvOneOrMore(buffer, 0, status, received); - User::WaitForRequest(status); + User::WaitForRequest(status); //Non blocking receive TInt err = status.Int(); int r = received(); @@ -1375,7 +1335,7 @@ void QSymbianSocketEnginePrivate::setError(TInt symbianError) setError(QAbstractSocket::AddressInUseError, AddressInuseErrorString); break; case KErrPermissionDenied: - setError(QAbstractSocket::SocketAccessError, AddressProtectedErrorString); + setError(QAbstractSocket::SocketAccessError, AccessErrorString); break; case KErrNotSupported: setError(QAbstractSocket::UnsupportedSocketOperationError, OperationUnsupportedErrorString); @@ -1383,9 +1343,18 @@ void QSymbianSocketEnginePrivate::setError(TInt symbianError) case KErrNoMemory: setError(QAbstractSocket::SocketResourceError, ResourceErrorString); break; + case KErrCouldNotConnect: + setError(QAbstractSocket::ConnectionRefusedError, ConnectionRefusedErrorString); + break; + case KErrTimedOut: + setError(QAbstractSocket::NetworkError, ConnectionTimeOutErrorString); + break; + case KErrBadName: + setError(QAbstractSocket::NetworkError, InvalidAddressError); + break; default: socketError = QAbstractSocket::NetworkError; - socketErrorString = QString::number(symbianError); + socketErrorString = QSystemError(symbianError, QSystemError::NativeError).toString(); break; } hasSetSocketError = true; -- cgit v0.12 From 4a8d3f4fb3830536a4a873f3c6bbf98fcdcd63a9 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 1 Feb 2011 19:55:12 +0000 Subject: Clean up TODO and FIXME that are done Reviewed-by: Markus Goetz --- src/network/socket/qsymbiansocketengine.cpp | 34 ++++++++++++++--------------- src/network/socket/qsymbiansocketengine_p.h | 4 ---- 2 files changed, 17 insertions(+), 21 deletions(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index df0675e..5649a18 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -538,10 +538,21 @@ void QSymbianSocketEngine::setSendBufferSize(qint64 size) setOption(SendBufferSocketOption, size); } +/*! + Connects to the remote host name given by \a name on port \a + port. When this function is called, the upper-level will not + perform a hostname lookup. + + The native socket engine does not support this operation, + but some other socket engines (notably proxy-based ones) do. +*/ bool QSymbianSocketEngine::connectToHostByName(const QString &name, quint16 port) { - // FIXME for engines that support hostnames.. not for us then i guess. - + Q_UNUSED(name); + Q_UNUSED(port); + Q_D(QSymbianSocketEngine); + d->setError(QAbstractSocket::UnsupportedSocketOperationError, + QSymbianSocketEnginePrivate::OperationUnsupportedErrorString); return false; } @@ -737,8 +748,6 @@ bool QSymbianSocketEngine::hasPendingDatagrams() const int nbytes; TInt err = d->nativeSocket.GetOpt(KSOReadBytesPending,KSOLSocket, nbytes); return err == KErrNone && nbytes > 0; - //TODO: this is pretty horrible too... - // FIXME why? } qint64 QSymbianSocketEngine::pendingDatagramSize() const @@ -770,9 +779,9 @@ qint64 QSymbianSocketEngine::readDatagram(char *data, qint64 maxSize, Q_D(QSymbianSocketEngine); TPtr8 buffer((TUint8*)data, (int)maxSize); TInetAddr addr; - TRequestStatus status; //TODO: OMG sync receive! + TRequestStatus status; d->nativeSocket.RecvFrom(buffer, addr, 0, status); - User::WaitForRequest(status); + User::WaitForRequest(status); //Non blocking receive if (status.Int()) { d->setError(QAbstractSocket::NetworkError, d->ReceiveDatagramErrorString); @@ -1036,7 +1045,6 @@ qint64 QSymbianSocketEngine::read(char *data, qint64 maxSize) return qint64(r); } -// FIXME wait vs select int QSymbianSocketEnginePrivate::nativeSelect(int timeout, bool selectForRead) const { bool readyRead = false; @@ -1062,8 +1070,6 @@ int QSymbianSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool //cancel asynchronous notifier (only one IOCTL allowed at a time) if (asyncSelect) asyncSelect->Cancel(); - //TODO: implement - //as above, but checking both read and write status at the same time TPckgBuf selectFlags; selectFlags() = KSockSelectExcept; @@ -1310,7 +1316,6 @@ void QSymbianSocketEnginePrivate::setError(QAbstractSocket::SocketError error, E } } -//TODO: use QSystemError class when file engine is merged to master void QSymbianSocketEnginePrivate::setError(TInt symbianError) { switch (symbianError) { @@ -1385,14 +1390,12 @@ bool QReadNotifier::event(QEvent *e) bool QSymbianSocketEngine::isReadNotificationEnabled() const { Q_D(const QSymbianSocketEngine); - // TODO return d->readNotifier && d->readNotifier->isEnabled(); } void QSymbianSocketEngine::setReadNotificationEnabled(bool enable) { Q_D(QSymbianSocketEngine); - // TODO if (d->readNotifier) { d->readNotifier->setEnabled(enable); } else if (enable && d->threadData->eventDispatcher) { @@ -1437,14 +1440,12 @@ bool QWriteNotifier::event(QEvent *e) bool QSymbianSocketEngine::isWriteNotificationEnabled() const { Q_D(const QSymbianSocketEngine); - // TODO return d->writeNotifier && d->writeNotifier->isEnabled(); } void QSymbianSocketEngine::setWriteNotificationEnabled(bool enable) { Q_D(QSymbianSocketEngine); - // TODO if (d->writeNotifier) { d->writeNotifier->setEnabled(enable); } else if (enable && d->threadData->eventDispatcher) { @@ -1488,7 +1489,6 @@ bool QExceptionNotifier::event(QEvent *e) bool QSymbianSocketEngine::isExceptionNotificationEnabled() const { Q_D(const QSymbianSocketEngine); - // TODO return d->exceptNotifier && d->exceptNotifier->isEnabled(); return false; } @@ -1497,7 +1497,6 @@ bool QSymbianSocketEngine::isExceptionNotificationEnabled() const void QSymbianSocketEngine::setExceptionNotificationEnabled(bool enable) { Q_D(QSymbianSocketEngine); - // TODO if (d->exceptNotifier) { d->exceptNotifier->setEnabled(enable); } else if (enable && d->threadData->eventDispatcher) { @@ -1674,7 +1673,8 @@ void QAsyncSelect::run() // return; m_inSocketEvent = true; m_selectBuf() &= m_selectFlags; //the select ioctl reports everything, so mask to only what we requested - //TODO: KSockSelectReadContinuation does what? + //KSockSelectReadContinuation is for reading datagrams in a mode that doesn't discard when the + //datagram is larger than the read buffer - Qt doesn't need to use this. if (iReadN && ((m_selectBuf() & KSockSelectRead) || iStatus != KErrNone)) { QEvent e(QEvent::SockAct); iReadN->event(&e); diff --git a/src/network/socket/qsymbiansocketengine_p.h b/src/network/socket/qsymbiansocketengine_p.h index df93fe6..a2904ae 100644 --- a/src/network/socket/qsymbiansocketengine_p.h +++ b/src/network/socket/qsymbiansocketengine_p.h @@ -60,8 +60,6 @@ #include #include #include -// TODO - QT_BEGIN_NAMESPACE @@ -121,7 +119,6 @@ public: int option(SocketOption option) const; bool setOption(SocketOption option, int value); - // FIXME actually implement bool waitForRead(int msecs = 30000, bool *timedOut = 0); bool waitForWrite(int msecs = 30000, bool *timedOut = 0); bool waitForReadOrWrite(bool *readyToRead, bool *readyToWrite, @@ -244,7 +241,6 @@ public: void setPortAndAddress(TInetAddr& nativeAddr, quint16 port, const QHostAddress &addr); void setError(TInt symbianError); - // FIXME int nativeSelect(int timeout, bool selectForRead) const; int nativeSelect(int timeout, bool checkRead, bool checkWrite, bool *selectForRead, bool *selectForWrite) const; -- cgit v0.12 From 027d9f026d3a668638ca6e687c687e0f4aa0cc02 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Wed, 2 Feb 2011 14:05:34 +0000 Subject: Add precondition checks to symbian socket engine entry points Reviewed-by: Markus Goetz --- src/network/socket/qsymbiansocketengine.cpp | 112 +++++++++++++++++++--------- 1 file changed, 75 insertions(+), 37 deletions(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index 5649a18..d6b893a 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -78,6 +78,7 @@ QT_BEGIN_NAMESPACE +#define Q_VOID // Common constructs #define Q_CHECK_VALID_SOCKETLAYER(function, returnValue) do { \ if (!isValid()) { \ @@ -186,9 +187,9 @@ bool QSymbianSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType so TUint type = (socketType == QAbstractSocket::UdpSocket) ? KSockDatagram : KSockStream; TUint protocol = (socketType == QAbstractSocket::UdpSocket) ? KProtocolInetUdp : KProtocolInetTcp; TInt err; - if (connection) - err = nativeSocket.Open(socketServer, family, type, protocol, *connection); - else +// if (connection) +// err = nativeSocket.Open(socketServer, family, type, protocol, *connection); +// else err = nativeSocket.Open(socketServer, family, type, protocol); //TODO: FIXME - deprecated API, make sure we always have a connection instead if (err != KErrNone) { @@ -296,7 +297,7 @@ bool QSymbianSocketEngine::initialize(QAbstractSocket::SocketType socketType, QA QString protocolStr = QLatin1String("UnknownProtocol"); if (protocol == QAbstractSocket::IPv4Protocol) protocolStr = QLatin1String("IPv4Protocol"); else if (protocol == QAbstractSocket::IPv6Protocol) protocolStr = QLatin1String("IPv6Protocol"); - qDebug("QNativeSocketEngine::initialize(type == %s, protocol == %s) failed: %s", + qDebug("QSymbianSocketEngine::initialize(type == %s, protocol == %s) failed: %s", typeStr.toLatin1().constData(), protocolStr.toLatin1().constData(), d->socketErrorString.toLatin1().constData()); #endif return false; @@ -323,7 +324,7 @@ bool QSymbianSocketEngine::initialize(QAbstractSocket::SocketType socketType, QA // Make sure we receive out-of-band data if (socketType == QAbstractSocket::TcpSocket && !setOption(ReceiveOutOfBandData, 1)) { - qWarning("QNativeSocketEngine::initialize unable to inline out-of-band data"); + qWarning("QSymbianSocketEngine::initialize unable to inline out-of-band data"); } @@ -364,7 +365,7 @@ bool QSymbianSocketEngine::initialize(int socketDescriptor, QAbstractSocket::Soc // determine socket type and protocol if (!d->fetchConnectionParameters()) { #if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEngine::initialize(socketDescriptor == %i) failed: %s", + qDebug("QSymbianSocketEngine::initialize(socketDescriptor == %i) failed: %s", socketDescriptor, d->socketErrorString.toLatin1().constData()); #endif d->socketDescriptor = -1; @@ -392,7 +393,7 @@ bool QSymbianSocketEngine::initialize(int socketDescriptor, QAbstractSocket::Soc // Make sure we receive out-of-band data if (d->socketType == QAbstractSocket::TcpSocket && !setOption(ReceiveOutOfBandData, 1)) { - qWarning("QNativeSocketEngine::initialize unable to inline out-of-band data"); + qWarning("QSymbianSocketEngine::initialize unable to inline out-of-band data"); } } @@ -428,8 +429,7 @@ int QSymbianSocketEngine::socketDescriptor() const bool QSymbianSocketEngine::setOption(QAbstractSocketEngine::SocketOption opt, int v) { Q_D(QSymbianSocketEngine); - if (!isValid()) - return false; + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setOption(), false); TUint n = 0; TUint level = KSOLSocket; // default @@ -449,8 +449,7 @@ bool QSymbianSocketEngine::setOption(QAbstractSocketEngine::SocketOption opt, in int QSymbianSocketEngine::option(QAbstractSocketEngine::SocketOption opt) const { Q_D(const QSymbianSocketEngine); - if (!isValid()) - return -1; + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::option(), -1); TUint n; TUint level = KSOLSocket; // default @@ -520,21 +519,25 @@ bool QSymbianSocketEnginePrivate::translateSocketOption(QAbstractSocketEngine::S qint64 QSymbianSocketEngine::receiveBufferSize() const { + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::receiveBufferSize(), -1); return option(ReceiveBufferSocketOption); } void QSymbianSocketEngine::setReceiveBufferSize(qint64 size) { + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setReceiveBufferSize(), Q_VOID); setOption(ReceiveBufferSocketOption, size); } qint64 QSymbianSocketEngine::sendBufferSize() const { + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setSendBufferSize(), -1); return option(SendBufferSocketOption); } void QSymbianSocketEngine::setSendBufferSize(qint64 size) { + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setSendBufferSize(), Q_VOID); setOption(SendBufferSocketOption, size); } @@ -577,6 +580,7 @@ void QSymbianSocketEngine::connectionNotification() bool QSymbianSocketEngine::connectToHost(const QHostAddress &addr, quint16 port) { Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::connectToHost(), false); #ifdef QNATIVESOCKETENGINE_DEBUG qDebug("QSymbianSocketEngine::connectToHost() : %d ", d->socketDescriptor); @@ -620,7 +624,7 @@ bool QSymbianSocketEngine::connectToHost(const QHostAddress &addr, quint16 port) } #if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeConnect(%s, %i) == true", + qDebug("QSymbianSocketEngine::Connect(%s, %i) == true", addr.toString().toLatin1().constData(), port); #endif @@ -632,12 +636,12 @@ bool QSymbianSocketEngine::connectToHost(const QHostAddress &addr, quint16 port) bool QSymbianSocketEngine::bind(const QHostAddress &address, quint16 port) { Q_D(QSymbianSocketEngine); - Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::bind(), false); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::bind(), false); if (!d->checkProxy(address)) return false; - Q_CHECK_STATE(QNativeSocketEngine::bind(), QAbstractSocket::UnconnectedState, false); + Q_CHECK_STATE(QSymbianSocketEngine::bind(), QAbstractSocket::UnconnectedState, false); TInetAddr nativeAddr; d->setPortAndAddress(nativeAddr, port, address); @@ -652,7 +656,7 @@ bool QSymbianSocketEngine::bind(const QHostAddress &address, quint16 port) d->setError(err); #if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QSymbianSocketEnginePrivate::nativeBind(%s, %i) == false (%s)", + qDebug("QSymbianSocketEngine::bind(%s, %i) == false (%s)", address.toString().toLatin1().constData(), port, d->socketErrorString.toLatin1().constData()); #endif @@ -660,7 +664,7 @@ bool QSymbianSocketEngine::bind(const QHostAddress &address, quint16 port) } #if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QSymbianSocketEnginePrivate::nativeBind(%s, %i) == true", + qDebug("QSymbianSocketEngine::bind(%s, %i) == true", address.toString().toLatin1().constData(), port); #endif d->socketState = QAbstractSocket::BoundState; @@ -672,21 +676,24 @@ bool QSymbianSocketEngine::bind(const QHostAddress &address, quint16 port) bool QSymbianSocketEngine::listen() { Q_D(QSymbianSocketEngine); - // TODO the value 50 is from the QNativeSocketEngine. Maybe it's a bit too much + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::listen(), false); + Q_CHECK_STATE(QSymbianSocketEngine::listen(), QAbstractSocket::BoundState, false); + Q_CHECK_TYPE(QSymbianSocketEngine::listen(), QAbstractSocket::TcpSocket, false); + // TODO the value 50 is from the QNativeSocketEngine. Maybe it's a bit too much // for a mobile platform TInt err = d->nativeSocket.Listen(50); if (err) { d->setError(err); #if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QSymbianSocketEnginePrivate::nativeListen() == false (%s)", + qDebug("QSymbianSocketEngine::listen() == false (%s)", d->socketErrorString.toLatin1().constData()); #endif return false; } #if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QSymbianSocketEnginePrivate::nativeListen() == true"); + qDebug("QSymbianSocketEngine::listen() == true"); #endif d->socketState = QAbstractSocket::ListeningState; @@ -707,7 +714,7 @@ int QSymbianSocketEngine::accept() if (status.Int()) { blankSocket.Close(); if (status != KErrWouldBlock) - qWarning("QSymbianSocketEnginePrivate::nativeAccept() - error %d", status.Int()); + qWarning("QSymbianSocketEngine::accept() - error %d", status.Int()); return -1; } @@ -724,8 +731,8 @@ int QSymbianSocketEngine::accept() qint64 QSymbianSocketEngine::bytesAvailable() const { Q_D(const QSymbianSocketEngine); - Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::bytesAvailable(), -1); - Q_CHECK_NOT_STATE(QNativeSocketEngine::bytesAvailable(), QAbstractSocket::UnconnectedState, false); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::bytesAvailable(), -1); + Q_CHECK_NOT_STATE(QSymbianSocketEngine::bytesAvailable(), QAbstractSocket::UnconnectedState, false); int nbytes = 0; qint64 available = 0; TInt err = d->nativeSocket.GetOpt(KSOReadBytesPending, KSOLSocket, nbytes); @@ -734,7 +741,7 @@ qint64 QSymbianSocketEngine::bytesAvailable() const available = (qint64) nbytes; #if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QSymbianSocketEnginePrivate::nativeBytesAvailable() == %lli", available); + qDebug("QSymbianSocketEngine::bytesAvailable() == %lli", available); #endif return available; } @@ -742,9 +749,9 @@ qint64 QSymbianSocketEngine::bytesAvailable() const bool QSymbianSocketEngine::hasPendingDatagrams() const { Q_D(const QSymbianSocketEngine); - Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::hasPendingDatagrams(), false); - Q_CHECK_NOT_STATE(QNativeSocketEngine::hasPendingDatagrams(), QAbstractSocket::UnconnectedState, false); - Q_CHECK_TYPE(QNativeSocketEngine::hasPendingDatagrams(), QAbstractSocket::UdpSocket, false); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::hasPendingDatagrams(), false); + Q_CHECK_NOT_STATE(QSymbianSocketEngine::hasPendingDatagrams(), QAbstractSocket::UnconnectedState, false); + Q_CHECK_TYPE(QSymbianSocketEngine::hasPendingDatagrams(), QAbstractSocket::UdpSocket, false); int nbytes; TInt err = d->nativeSocket.GetOpt(KSOReadBytesPending,KSOLSocket, nbytes); return err == KErrNone && nbytes > 0; @@ -753,6 +760,8 @@ bool QSymbianSocketEngine::hasPendingDatagrams() const qint64 QSymbianSocketEngine::pendingDatagramSize() const { Q_D(const QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::pendingDatagramSize(), false); + Q_CHECK_TYPE(QSymbianSocketEngine::hasPendingDatagrams(), QAbstractSocket::UdpSocket, false); int nbytes; TInt err = d->nativeSocket.GetOpt(KSOReadBytesPending,KSOLSocket, nbytes); if (nbytes > 0) { @@ -777,6 +786,8 @@ qint64 QSymbianSocketEngine::readDatagram(char *data, qint64 maxSize, QHostAddress *address, quint16 *port) { Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::readDatagram(), -1); + Q_CHECK_TYPE(QSymbianSocketEngine::readDatagram(), QAbstractSocket::UdpSocket, false); TPtr8 buffer((TUint8*)data, (int)maxSize); TInetAddr addr; TRequestStatus status; @@ -791,7 +802,7 @@ qint64 QSymbianSocketEngine::readDatagram(char *data, qint64 maxSize, #if defined (QNATIVESOCKETENGINE_DEBUG) int len = buffer.Length(); - qDebug("QSymbianSocketEnginePrivate::nativeReceiveDatagram(%p \"%s\", %lli, %s, %i) == %lli", + qDebug("QSymbianSocketEngine::receiveDatagram(%p \"%s\", %lli, %s, %i) == %lli", data, qt_prettyDebug(data, qMin(len, ssize_t(16)), len).data(), maxSize, address ? address->toString().toLatin1().constData() : "(nil)", port ? *port : 0, (qint64) len); @@ -807,8 +818,8 @@ qint64 QSymbianSocketEngine::writeDatagram(const char *data, qint64 len, const QHostAddress &host, quint16 port) { Q_D(QSymbianSocketEngine); - Q_CHECK_VALID_SOCKETLAYER(QNativeSocketEngine::writeDatagram(), -1); - Q_CHECK_TYPE(QNativeSocketEngine::writeDatagram(), QAbstractSocket::UdpSocket, -1); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::writeDatagram(), -1); + Q_CHECK_TYPE(QSymbianSocketEngine::writeDatagram(), QAbstractSocket::UdpSocket, -1); TPtrC8 buffer((TUint8*)data, (int)len); TInetAddr addr; d->setPortAndAddress(addr, port, host); @@ -920,7 +931,7 @@ void QSymbianSocketEngine::close() return; Q_D(QSymbianSocketEngine); #if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QSymbianSocketEnginePrivate::nativeClose()"); + qDebug("QSymbianSocketEngine::close()"); #endif if (d->readNotifier) @@ -973,6 +984,8 @@ void QSymbianSocketEngine::close() qint64 QSymbianSocketEngine::write(const char *data, qint64 len) { Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::write(), -1); + Q_CHECK_STATE(QSymbianSocketEngine::write(), QAbstractSocket::ConnectedState, -1); TPtrC8 buffer((TUint8*)data, (int)len); TSockXfrLength sentBytes = 0; TRequestStatus status; @@ -1002,7 +1015,7 @@ qint64 QSymbianSocketEngine::write(const char *data, qint64 len) } #if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QSymbianSocketEnginePrivate::nativeWrite(%p \"%s\", %llu) == %i", + qDebug("QSymbianSocketEngine::write(%p \"%s\", %llu) == %i", data, qt_prettyDebug(data, qMin((int) len, 16), (int) len).data(), len, (int) sentBytes()); #endif @@ -1014,10 +1027,8 @@ qint64 QSymbianSocketEngine::write(const char *data, qint64 len) qint64 QSymbianSocketEngine::read(char *data, qint64 maxSize) { Q_D(QSymbianSocketEngine); - if (!isValid()) { - qWarning("QSymbianSocketEnginePrivate::nativeRead: Invalid socket"); - return -1; - } + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::read(), -1); + Q_CHECK_STATES(QSymbianSocketEngine::read(), QAbstractSocket::ConnectedState, QAbstractSocket::BoundState, -1); TPtr8 buffer((TUint8*)data, (int)maxSize); TSockXfrLength received = 0; @@ -1037,7 +1048,7 @@ qint64 QSymbianSocketEngine::read(char *data, qint64 maxSize) } #if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QNativeSocketEnginePrivate::nativeRead(%p \"%s\", %llu) == %i", + qDebug("QSymbianSocketEngine::read(%p \"%s\", %llu) == %i", data, qt_prettyDebug(data, qMin(r, ssize_t(16)), r).data(), maxSize, r); #endif @@ -1131,6 +1142,9 @@ bool QSymbianSocketEngine::joinMulticastGroup(const QHostAddress &groupAddress, const QNetworkInterface &iface) { Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::joinMulticastGroup(), false); + Q_CHECK_STATE(QSymbianSocketEngine::joinMulticastGroup(), QAbstractSocket::BoundState, false); + Q_CHECK_TYPE(QSymbianSocketEngine::joinMulticastGroup(), QAbstractSocket::UdpSocket, false); return d->multicastGroupMembershipHelper(groupAddress, iface, KSoIp6JoinGroup); } @@ -1138,6 +1152,9 @@ bool QSymbianSocketEngine::leaveMulticastGroup(const QHostAddress &groupAddress, const QNetworkInterface &iface) { Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::leaveMulticastGroup(), false); + Q_CHECK_STATE(QSymbianSocketEngine::leaveMulticastGroup(), QAbstractSocket::BoundState, false); + Q_CHECK_TYPE(QSymbianSocketEngine::leaveMulticastGroup(), QAbstractSocket::UdpSocket, false); return d->multicastGroupMembershipHelper(groupAddress, iface, KSoIp6LeaveGroup); } @@ -1166,12 +1183,18 @@ bool QSymbianSocketEnginePrivate::multicastGroupMembershipHelper(const QHostAddr QNetworkInterface QSymbianSocketEngine::multicastInterface() const { //TODO + const Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::multicastInterface(), QNetworkInterface()); + Q_CHECK_TYPE(QSymbianSocketEngine::multicastInterface(), QAbstractSocket::UdpSocket, QNetworkInterface()); return QNetworkInterface(); } bool QSymbianSocketEngine::setMulticastInterface(const QNetworkInterface &iface) { //TODO - this is possibly a unix'ism as the RConnection on which the socket was created is probably controlling this + Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setMulticastInterface(), false); + Q_CHECK_TYPE(QSymbianSocketEngine::setMulticastInterface(), QAbstractSocket::UdpSocket, false); return false; } @@ -1197,7 +1220,7 @@ bool QSymbianSocketEnginePrivate::checkProxy(const QHostAddress &address) if (proxy.type() != QNetworkProxy::DefaultProxy && proxy.type() != QNetworkProxy::NoProxy) { - // QNativeSocketEngine doesn't do proxies + // QSymbianSocketEngine doesn't do proxies setError(QAbstractSocket::UnsupportedSocketOperationError, InvalidProxyTypeString); return false; @@ -1390,12 +1413,14 @@ bool QReadNotifier::event(QEvent *e) bool QSymbianSocketEngine::isReadNotificationEnabled() const { Q_D(const QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::isReadNotificationEnabled(), false); return d->readNotifier && d->readNotifier->isEnabled(); } void QSymbianSocketEngine::setReadNotificationEnabled(bool enable) { Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setReadNotificationEnabled(), Q_VOID); if (d->readNotifier) { d->readNotifier->setEnabled(enable); } else if (enable && d->threadData->eventDispatcher) { @@ -1440,12 +1465,14 @@ bool QWriteNotifier::event(QEvent *e) bool QSymbianSocketEngine::isWriteNotificationEnabled() const { Q_D(const QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::isWriteNotificationEnabled(), false); return d->writeNotifier && d->writeNotifier->isEnabled(); } void QSymbianSocketEngine::setWriteNotificationEnabled(bool enable) { Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setWriteNotificationEnabled(), Q_VOID); if (d->writeNotifier) { d->writeNotifier->setEnabled(enable); } else if (enable && d->threadData->eventDispatcher) { @@ -1489,6 +1516,7 @@ bool QExceptionNotifier::event(QEvent *e) bool QSymbianSocketEngine::isExceptionNotificationEnabled() const { Q_D(const QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::isExceptionNotificationEnabled(), false); return d->exceptNotifier && d->exceptNotifier->isEnabled(); return false; } @@ -1497,6 +1525,7 @@ bool QSymbianSocketEngine::isExceptionNotificationEnabled() const void QSymbianSocketEngine::setExceptionNotificationEnabled(bool enable) { Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setExceptionNotificationEnabled(), Q_VOID); if (d->exceptNotifier) { d->exceptNotifier->setEnabled(enable); } else if (enable && d->threadData->eventDispatcher) { @@ -1514,6 +1543,9 @@ void QSymbianSocketEngine::setExceptionNotificationEnabled(bool enable) bool QSymbianSocketEngine::waitForRead(int msecs, bool *timedOut) { Q_D(const QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::waitForRead(), false); + Q_CHECK_NOT_STATE(QSymbianSocketEngine::waitForRead(), + QAbstractSocket::UnconnectedState, false); if (timedOut) *timedOut = false; @@ -1536,6 +1568,9 @@ bool QSymbianSocketEngine::waitForRead(int msecs, bool *timedOut) bool QSymbianSocketEngine::waitForWrite(int msecs, bool *timedOut) { Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::waitForWrite(), false); + Q_CHECK_NOT_STATE(QSymbianSocketEngine::waitForWrite(), + QAbstractSocket::UnconnectedState, false); if (timedOut) *timedOut = false; @@ -1561,6 +1596,9 @@ bool QSymbianSocketEngine::waitForReadOrWrite(bool *readyToRead, bool *readyToWr int msecs, bool *timedOut) { Q_D(QSymbianSocketEngine); + Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::waitForWrite(), false); + Q_CHECK_NOT_STATE(QSymbianSocketEngine::waitForReadOrWrite(), + QAbstractSocket::UnconnectedState, false); int ret = d->nativeSelect(msecs, checkRead, checkWrite, readyToRead, readyToWrite); -- cgit v0.12 From d0c0aaf859452349c5cd64cbdba4ebb722c7722f Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Wed, 12 Jan 2011 15:21:45 +0000 Subject: Fix for using search paths with a dirty path Opening "searchpath:/file" and other non clean paths was failing Reviewed-by: joao --- src/corelib/io/qfilesystemengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/io/qfilesystemengine.cpp b/src/corelib/io/qfilesystemengine.cpp index d9d802e..799c109 100644 --- a/src/corelib/io/qfilesystemengine.cpp +++ b/src/corelib/io/qfilesystemengine.cpp @@ -168,7 +168,7 @@ static bool _q_resolveEntryAndCreateLegacyEngine_recursive(QFileSystemEntry &ent const QStringList &paths = QDir::searchPaths(filePath.left(prefixSeparator)); for (int i = 0; i < paths.count(); i++) { - entry = QFileSystemEntry(paths.at(i) % QLatin1Char('/') % filePath.mid(prefixSeparator + 1)); + entry = QFileSystemEntry(QDir::cleanPath(paths.at(i) % QLatin1Char('/') % filePath.mid(prefixSeparator + 1))); // Recurse! if (_q_resolveEntryAndCreateLegacyEngine_recursive(entry, data, engine, true)) return true; -- cgit v0.12 From 97512b51ca8addc4fe1f8b5a4f7af14a13d4fd83 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Thu, 3 Feb 2011 12:16:35 +0000 Subject: Fix random crashes when bearer suddenly goes down 1. QNetworkSession being deleted from the closed signal caused data abort or E32User-CBase 49 panics. (both observed) 2. Potential E32User-CBase 46 panic in ConnectionProgressNotifier::StartNotifications() Reviewed-by: Aaron Tunney Reviewed-By: Markus Goetz Task-Number: QTBUG-17196 --- src/network/access/qnetworkaccessmanager.cpp | 7 ++++--- src/network/bearer/qnetworksession.cpp | 3 +++ src/network/bearer/qnetworksession.h | 3 +++ src/plugins/bearer/symbian/qnetworksession_impl.cpp | 6 +++--- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index 7d37375..9c5a035 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -1358,10 +1358,11 @@ void QNetworkAccessManagerPrivate::createSession(const QNetworkConfiguration &co networkSession = QSharedNetworkSessionManager::getSession(config); - QObject::connect(networkSession.data(), SIGNAL(opened()), q, SIGNAL(networkSessionConnected())); - QObject::connect(networkSession.data(), SIGNAL(closed()), q, SLOT(_q_networkSessionClosed())); + QObject::connect(networkSession.data(), SIGNAL(opened()), q, SIGNAL(networkSessionConnected()), Qt::QueuedConnection); + //QueuedConnection is used to avoid deleting the networkSession inside its closed signal + QObject::connect(networkSession.data(), SIGNAL(closed()), q, SLOT(_q_networkSessionClosed()), Qt::QueuedConnection); QObject::connect(networkSession.data(), SIGNAL(stateChanged(QNetworkSession::State)), - q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State))); + q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State)), Qt::QueuedConnection); _q_networkSessionStateChanged(networkSession->state()); } diff --git a/src/network/bearer/qnetworksession.cpp b/src/network/bearer/qnetworksession.cpp index 41a8854..474ac6d 100644 --- a/src/network/bearer/qnetworksession.cpp +++ b/src/network/bearer/qnetworksession.cpp @@ -250,6 +250,9 @@ QNetworkSession::QNetworkSession(const QNetworkConfiguration &connectionConfig, } } } + + qRegisterMetaType(); + qRegisterMetaType(); } /*! diff --git a/src/network/bearer/qnetworksession.h b/src/network/bearer/qnetworksession.h index 717e085..da0c486 100644 --- a/src/network/bearer/qnetworksession.h +++ b/src/network/bearer/qnetworksession.h @@ -140,6 +140,9 @@ private: QNetworkSessionPrivate *d; }; +Q_DECLARE_METATYPE(QNetworkSession::State); +Q_DECLARE_METATYPE(QNetworkSession::SessionError); + #ifndef QT_MOBILITY_BEARER QT_END_NAMESPACE #else diff --git a/src/plugins/bearer/symbian/qnetworksession_impl.cpp b/src/plugins/bearer/symbian/qnetworksession_impl.cpp index 759c86a..bbaf47b 100644 --- a/src/plugins/bearer/symbian/qnetworksession_impl.cpp +++ b/src/plugins/bearer/symbian/qnetworksession_impl.cpp @@ -1550,8 +1550,8 @@ void ConnectionProgressNotifier::StartNotifications() { if (!IsActive()) { SetActive(); + iConnection.ProgressNotification(iProgress, iStatus); } - iConnection.ProgressNotification(iProgress, iStatus); } void ConnectionProgressNotifier::StopNotifications() @@ -1567,10 +1567,10 @@ void ConnectionProgressNotifier::DoCancel() void ConnectionProgressNotifier::RunL() { if (iStatus == KErrNone) { - QT_TRYCATCH_LEAVING(iOwner.handleSymbianConnectionStatusChange(iProgress().iStage, iProgress().iError)); - SetActive(); iConnection.ProgressNotification(iProgress, iStatus); + // warning, this object may be deleted in the callback - do nothing after handleSymbianConnectionStatusChange + QT_TRYCATCH_LEAVING(iOwner.handleSymbianConnectionStatusChange(iProgress().iStage, iProgress().iError)); } } -- cgit v0.12 From cb0150aec0099ecc1569b20b58a75cdf9e5a5177 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Thu, 27 Jan 2011 14:57:59 +0000 Subject: add qscopedvaluerollback autotest to corelib.pro --- tests/auto/corelib.pro | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/auto/corelib.pro b/tests/auto/corelib.pro index 3451b53..6810f76 100644 --- a/tests/auto/corelib.pro +++ b/tests/auto/corelib.pro @@ -59,6 +59,7 @@ SUBDIRS=\ qresourceengine \ qringbuffer \ qscopedpointer \ + qscopedvaluerollback \ qsemaphore \ qsequentialanimationgroup \ qset \ -- cgit v0.12 From 9d7a1b187a76db52283429e38a0210c1dac82bf5 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Thu, 27 Jan 2011 15:02:08 +0000 Subject: Fix GCC compiler warning --- src/corelib/tools/qscopedvaluerollback.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/tools/qscopedvaluerollback.h b/src/corelib/tools/qscopedvaluerollback.h index d344ed8..e874428 100644 --- a/src/corelib/tools/qscopedvaluerollback.h +++ b/src/corelib/tools/qscopedvaluerollback.h @@ -72,7 +72,7 @@ private: T& varRef; T oldValue; - Q_DISABLE_COPY(QScopedValueRollback); + Q_DISABLE_COPY(QScopedValueRollback) }; QT_END_NAMESPACE -- cgit v0.12 From b9307547c717606e08661cf474eeaf81cc0789e6 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 28 Jan 2011 14:52:41 +0100 Subject: Fix for linux build error --- tests/auto/qscopedvaluerollback/tst_qscopedvaluerollback.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/qscopedvaluerollback/tst_qscopedvaluerollback.cpp b/tests/auto/qscopedvaluerollback/tst_qscopedvaluerollback.cpp index fac5702..956253f 100644 --- a/tests/auto/qscopedvaluerollback/tst_qscopedvaluerollback.cpp +++ b/tests/auto/qscopedvaluerollback/tst_qscopedvaluerollback.cpp @@ -200,4 +200,4 @@ void tst_QScopedValueRollback::earlyExitScope_helper(int exitpoint, int& member) } QTEST_MAIN(tst_QScopedValueRollback) -#include "tst_QScopedValueRollback.moc" +#include "tst_qscopedvaluerollback.moc" -- cgit v0.12 From bf024acae38226a2430d8c82b0f940781e33a7ef Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 7 Feb 2011 17:39:43 +0000 Subject: rebuild configure.exe --- configure.exe | Bin 1326592 -> 1397760 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/configure.exe b/configure.exe index 293d667..9d450b5 100755 Binary files a/configure.exe and b/configure.exe differ -- cgit v0.12 From b1fa3580515e7f10a9bd06b6a9e7733635f95cab Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 8 Feb 2011 16:05:53 +0000 Subject: Workaround public header depending on private in symbian^3 f32file.h (public) depends on e32svr.h (private), and in symbian^3 the private headers have been moved to a different include path. Reviewed-by: axis --- mkspecs/features/qt_functions.prf | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mkspecs/features/qt_functions.prf b/mkspecs/features/qt_functions.prf index 964e13b..bc1a297 100644 --- a/mkspecs/features/qt_functions.prf +++ b/mkspecs/features/qt_functions.prf @@ -46,7 +46,12 @@ defineTest(qtAddLibrary) { } } symbian { - isEqual(LIB_NAME, QtGui) { + isEqual(LIB_NAME, QtCore) { + #workaround for dependency from f32file.h on e32svr.h which has moved location in symbian3 + contains(SYMBIAN_VERSION, Symbian3) { + INCLUDEPATH *= $$OS_LAYER_SYSTEMINCLUDE + } + } else:isEqual(LIB_NAME, QtGui) { # Needed for #include because qs60mainapplication.h includes aknapp.h INCLUDEPATH *= $$MW_LAYER_SYSTEMINCLUDE } else:isEqual(LIB_NAME, QtWebKit) { -- cgit v0.12 From 42adaaa0dffa9df387a145181bc97ee3bb9a4c7b Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Wed, 16 Feb 2011 13:52:12 +0000 Subject: Fix thread starvation when processEvents() is called in a tight loop One of the qftp test cases calls processEvents() in a tight loop instead of using an event loop. This was causing the application to hang on symbian as it blocked a lower priority system thread and the WLAN connection never completed. Although calling processEvents in a tight loop is bad practice, it works on other OS where thread priorities are dynamic. Reviewed-by: mread --- src/corelib/kernel/qeventdispatcher_symbian.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/corelib/kernel/qeventdispatcher_symbian.cpp b/src/corelib/kernel/qeventdispatcher_symbian.cpp index b3a3d4d..0b7682c 100644 --- a/src/corelib/kernel/qeventdispatcher_symbian.cpp +++ b/src/corelib/kernel/qeventdispatcher_symbian.cpp @@ -818,6 +818,14 @@ bool QEventDispatcherSymbian::processEvents ( QEventLoop::ProcessEventsFlags fla CActiveScheduler::Current()->WaitForAnyRequest(); } else { if (thread.RequestCount() == 0) { +#ifdef QT_SYMBIAN_PRIORITY_DROP + if (idleDetectorThread()->hasRun()) { + m_lastIdleRequestTimer.start(); + idleDetectorThread()->kick(); + } else if (m_lastIdleRequestTimer.elapsed() > maxBusyTime) { + User::AfterHighRes(m_delay); + } +#endif break; } // This one should return without delay. -- cgit v0.12 From 44ef44bc3826c78a10bcf02d3357bf6332c6c3ed Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Thu, 17 Feb 2011 13:27:45 +0000 Subject: Explicit network session for QNetworkAccessManager Implemented a tunnel to get the QNetworkSession from QNetworkAccessManager down to the socket engine. This is currently a private API for QNAM. This patch only implements the FTP backend - the other backends are to follow. On Symbian, the native socket engine will extract the native session (RConnection) from the QNetworkSession implementation, and use that to open sockets using the explicitly specified session. When no session is specified on the socket (default for networking usage outside of QNAM) then the socket is opened with no RConnection specified, which allows the IP stack to find any route via an open interface. The QFtp autotest is enhanced to test QFtp with an explicit session as well as implicit connectivity (where a QNetworkSession is opened by the user, and then QFtp is used without a specified connection). This autotest gives better coverage than the FTP test cases in QNetworkReply. Reviewed-by: Markus Goetz --- src/network/access/qftp.cpp | 17 +++++ src/network/access/qnetworkaccessbackend.cpp | 7 +- src/network/access/qnetworkaccessftpbackend.cpp | 4 + src/network/bearer/qnetworksession.cpp | 9 +++ src/network/bearer/qnetworksession_p.h | 11 +++ src/network/socket/qabstractsocket.cpp | 8 ++ src/network/socket/qsymbiansocketengine.cpp | 31 ++++++-- src/network/socket/qsymbiansocketengine_p.h | 5 +- src/network/socket/qtcpserver.cpp | 8 ++ src/network/ssl/qsslsocket.cpp | 4 + .../bearer/symbian/qnetworksession_impl.cpp | 5 ++ src/plugins/bearer/symbian/qnetworksession_impl.h | 3 +- tests/auto/qftp/tst_qftp.cpp | 88 ++++++++++++++++++++-- 13 files changed, 182 insertions(+), 18 deletions(-) diff --git a/src/network/access/qftp.cpp b/src/network/access/qftp.cpp index ccc20e6..45fc11f 100644 --- a/src/network/access/qftp.cpp +++ b/src/network/access/qftp.cpp @@ -319,6 +319,10 @@ void QFtpDTP::connectToHost(const QString & host, quint16 port) socket = 0; } socket = new QTcpSocket(this); +#ifndef QT_NO_BEARERMANAGEMENT + //copy network session down to the socket + socket->setProperty("_q_networksession", property("_q_networksession")); +#endif socket->setObjectName(QLatin1String("QFtpDTP Passive state socket")); connect(socket, SIGNAL(connected()), SLOT(socketConnected())); connect(socket, SIGNAL(readyRead()), SLOT(socketReadyRead())); @@ -331,6 +335,10 @@ void QFtpDTP::connectToHost(const QString & host, quint16 port) int QFtpDTP::setupListener(const QHostAddress &address) { +#ifndef QT_NO_BEARERMANAGEMENT + //copy network session down to the socket + listener.setProperty("_q_networksession", property("_q_networksession")); +#endif if (!listener.isListening() && !listener.listen(address, 0)) return -1; return listener.serverPort(); @@ -808,6 +816,11 @@ QFtpPI::QFtpPI(QObject *parent) : void QFtpPI::connectToHost(const QString &host, quint16 port) { emit connectState(QFtp::HostLookup); +#ifndef QT_NO_BEARERMANAGEMENT + //copy network session down to the socket & DTP + commandSocket.setProperty("_q_networksession", property("_q_networksession")); + dtp.setProperty("_q_networksession", property("_q_networksession")); +#endif commandSocket.connectToHost(host, port); } @@ -2240,6 +2253,10 @@ void QFtpPrivate::_q_startNextCommand() c->rawCmds.clear(); _q_piFinished(QLatin1String("Proxy set to ") + proxyHost + QLatin1Char(':') + QString::number(proxyPort)); } else if (c->command == QFtp::ConnectToHost) { +#ifndef QT_NO_BEARERMANAGEMENT + //copy network session down to the PI + pi.setProperty("_q_networksession", q->property("_q_networksession")); +#endif if (!proxyHost.isEmpty()) { host = c->rawCmds[0]; port = c->rawCmds[1].toUInt(); diff --git a/src/network/access/qnetworkaccessbackend.cpp b/src/network/access/qnetworkaccessbackend.cpp index fd1fa60..de40256 100644 --- a/src/network/access/qnetworkaccessbackend.cpp +++ b/src/network/access/qnetworkaccessbackend.cpp @@ -46,7 +46,7 @@ #include "qnetworkreply_p.h" #include "QtCore/qhash.h" #include "QtCore/qmutex.h" -#include "QtNetwork/qnetworksession.h" +#include "QtNetwork/private/qnetworksession_p.h" #include "qnetworkaccesscachebackend_p.h" #include "qabstractnetworkcache.h" @@ -96,6 +96,11 @@ QNetworkAccessBackend *QNetworkAccessManagerPrivate::findBackend(QNetworkAccessM QNetworkAccessBackend *backend = (*it)->create(op, request); if (backend) { backend->manager = this; +#ifndef QT_NO_BEARERMANAGEMENT + //copy network session down to the backend + if (networkSession) + backend->setProperty("_q_networksession", QVariant::fromValue(networkSession)); +#endif return backend; // found a factory that handled our request } ++it; diff --git a/src/network/access/qnetworkaccessftpbackend.cpp b/src/network/access/qnetworkaccessftpbackend.cpp index e34e6bb..3ad1961 100644 --- a/src/network/access/qnetworkaccessftpbackend.cpp +++ b/src/network/access/qnetworkaccessftpbackend.cpp @@ -153,6 +153,10 @@ void QNetworkAccessFtpBackend::open() if (!objectCache->requestEntry(cacheKey, this, SLOT(ftpConnectionReady(QNetworkAccessCache::CacheableObject*)))) { ftp = new QNetworkAccessCachedFtpConnection; +#ifndef QT_NO_BEARERMANAGEMENT + //copy network session down to the QFtp + ftp->setProperty("_q_networksession", property("_q_networksession")); +#endif #ifndef QT_NO_NETWORKPROXY if (proxy.type() == QNetworkProxy::FtpCachingProxy) ftp->setProxy(proxy.hostName(), proxy.port()); diff --git a/src/network/bearer/qnetworksession.cpp b/src/network/bearer/qnetworksession.cpp index 553410e..0ddd10a 100644 --- a/src/network/bearer/qnetworksession.cpp +++ b/src/network/bearer/qnetworksession.cpp @@ -705,6 +705,15 @@ void QNetworkSession::disconnectNotify(const char *signal) d->setALREnabled(false); } +#ifdef Q_OS_SYMBIAN +RConnection* QNetworkSessionPrivate::nativeSession(QNetworkSession &s) +{ + if (!s.d) + return 0; + return s.d->nativeSession(); +} +#endif + #include "moc_qnetworksession.cpp" QT_END_NAMESPACE diff --git a/src/network/bearer/qnetworksession_p.h b/src/network/bearer/qnetworksession_p.h index 707ad37..e2fcfe6 100644 --- a/src/network/bearer/qnetworksession_p.h +++ b/src/network/bearer/qnetworksession_p.h @@ -55,9 +55,14 @@ #include "qnetworksession.h" #include "qnetworkconfiguration_p.h" +#include "QtCore/qsharedpointer.h" #ifndef QT_NO_BEARERMANAGEMENT +#ifdef Q_OS_SYMBIAN +class RConnection; +#endif + QT_BEGIN_NAMESPACE class Q_NETWORK_EXPORT QNetworkSessionPrivate : public QObject @@ -102,6 +107,10 @@ public: virtual quint64 bytesReceived() const = 0; virtual quint64 activeTime() const = 0; +#ifdef Q_OS_SYMBIAN + static RConnection* nativeSession(QNetworkSession&); + virtual RConnection* nativeSession() = 0; +#endif protected: inline QNetworkConfigurationPrivatePointer privateConfiguration(const QNetworkConfiguration &config) const { @@ -145,6 +154,8 @@ protected: QT_END_NAMESPACE +Q_DECLARE_METATYPE(QSharedPointer) + #endif // QT_NO_BEARERMANAGEMENT #endif // QNETWORKSESSIONPRIVATE_H diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index 3462538..af5f027 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -546,6 +546,10 @@ bool QAbstractSocketPrivate::initSocketLayer(QAbstractSocket::NetworkLayerProtoc resetSocketLayer(); socketEngine = QAbstractSocketEngine::createSocketEngine(q->socketType(), proxyInUse, q); +#ifndef QT_NO_BEARERMANAGEMENT + //copy network session down to the socket engine (if it has been set) + socketEngine->setProperty("_q_networksession", q->property("_q_networksession")); +#endif if (!socketEngine) { socketError = QAbstractSocket::UnsupportedSocketOperationError; q->setErrorString(QAbstractSocket::tr("Operation on socket is not supported")); @@ -1600,6 +1604,10 @@ bool QAbstractSocket::setSocketDescriptor(int socketDescriptor, SocketState sock d->resetSocketLayer(); d->socketEngine = QAbstractSocketEngine::createSocketEngine(socketDescriptor, this); +#ifndef QT_NO_BEARERMANAGEMENT + //copy network session down to the socket engine (if it has been set) + d->socketEngine->setProperty("_q_networksession", property("_q_networksession")); +#endif if (!d->socketEngine) { d->socketError = UnsupportedSocketOperationError; setErrorString(tr("Operation on socket is not supported")); diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index d6b893a..b9537c1 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -47,6 +47,7 @@ #include "qelapsedtimer.h" #include "qvarlengtharray.h" #include "qnetworkinterface.h" +#include "qnetworksession_p.h" #include #include #include @@ -186,10 +187,26 @@ bool QSymbianSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType so TUint family = KAfInet; // KAfInet6 is only used as an address family, not as a protocol family TUint type = (socketType == QAbstractSocket::UdpSocket) ? KSockDatagram : KSockStream; TUint protocol = (socketType == QAbstractSocket::UdpSocket) ? KProtocolInetUdp : KProtocolInetTcp; + + //Check if there is a user specified session + RConnection *connection = 0; + QVariant v(q->property("_q_networksession")); + if (v.isValid()) { + QSharedPointer s = qvariant_cast >(v); + connection = QNetworkSessionPrivate::nativeSession(*s); +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug() << "QSymbianSocketEnginePrivate::createNewSocket - _q_networksession was set" << connection; +#endif + } TInt err; -// if (connection) -// err = nativeSocket.Open(socketServer, family, type, protocol, *connection); -// else + if (connection) { + if (connection->SubSessionHandle()) + err = nativeSocket.Open(socketServer, family, type, protocol, *connection); + else { + setError(QAbstractSocket::NetworkError, SessionNotOpenErrorString); + return false; + } + } else err = nativeSocket.Open(socketServer, family, type, protocol); //TODO: FIXME - deprecated API, make sure we always have a connection instead if (err != KErrNone) { @@ -246,7 +263,6 @@ void QSymbianSocketEnginePrivate::setPortAndAddress(TInetAddr& nativeAddr, quint QSymbianSocketEnginePrivate::QSymbianSocketEnginePrivate() : socketDescriptor(-1), socketServer(QSymbianSocketManager::instance().getSocketServer()), - connection(QSymbianSocketManager::instance().defaultConnection()), readNotifier(0), writeNotifier(0), exceptNotifier(0), @@ -1330,9 +1346,12 @@ void QSymbianSocketEnginePrivate::setError(QAbstractSocket::SocketError error, E case InvalidProxyTypeString: socketErrorString = QSymbianSocketEngine::tr("The proxy type is invalid for this operation"); break; - case InvalidAddressError: + case InvalidAddressErrorString: socketErrorString = QSymbianSocketEngine::tr("The address is invalid for this operation"); break; + case SessionNotOpenErrorString: + socketErrorString = QSymbianSocketEngine::tr("The specified network session is not opened"); + break; case UnknownSocketErrorString: socketErrorString = QSymbianSocketEngine::tr("Unknown error"); break; @@ -1378,7 +1397,7 @@ void QSymbianSocketEnginePrivate::setError(TInt symbianError) setError(QAbstractSocket::NetworkError, ConnectionTimeOutErrorString); break; case KErrBadName: - setError(QAbstractSocket::NetworkError, InvalidAddressError); + setError(QAbstractSocket::NetworkError, InvalidAddressErrorString); break; default: socketError = QAbstractSocket::NetworkError; diff --git a/src/network/socket/qsymbiansocketengine_p.h b/src/network/socket/qsymbiansocketengine_p.h index a2904ae..bc39450 100644 --- a/src/network/socket/qsymbiansocketengine_p.h +++ b/src/network/socket/qsymbiansocketengine_p.h @@ -196,8 +196,6 @@ public: mutable RSocket nativeSocket; // From QtCore: RSocketServ& socketServer; - // From QtCore, check lifetime issues, also should be pulling this out of a QNetworkSession somehow: - RConnection *connection; mutable RTimer selectTimer; QSocketNotifier *readNotifier, *writeNotifier, *exceptNotifier; @@ -231,7 +229,8 @@ public: NotSocketErrorString, InvalidProxyTypeString, //symbian specific - InvalidAddressError, + InvalidAddressErrorString, + SessionNotOpenErrorString, UnknownSocketErrorString = -1 }; diff --git a/src/network/socket/qtcpserver.cpp b/src/network/socket/qtcpserver.cpp index e382830..6b012db 100644 --- a/src/network/socket/qtcpserver.cpp +++ b/src/network/socket/qtcpserver.cpp @@ -287,6 +287,10 @@ bool QTcpServer::listen(const QHostAddress &address, quint16 port) delete d->socketEngine; d->socketEngine = QAbstractSocketEngine::createSocketEngine(QAbstractSocket::TcpSocket, proxy, this); +#ifndef QT_NO_BEARERMANAGEMENT + //copy network session down to the socket engine (if it has been set) + d->socketEngine->setProperty("_q_networksession", property("_q_networksession")); +#endif if (!d->socketEngine) { d->serverSocketError = QAbstractSocket::UnsupportedSocketOperationError; d->serverSocketErrorString = tr("Operation on socket is not supported"); @@ -412,6 +416,10 @@ bool QTcpServer::setSocketDescriptor(int socketDescriptor) if (d->socketEngine) delete d->socketEngine; d->socketEngine = QAbstractSocketEngine::createSocketEngine(socketDescriptor, this); +#ifndef QT_NO_BEARERMANAGEMENT + //copy network session down to the socket engine (if it has been set) + d->socketEngine->setProperty("_q_networksession", property("_q_networksession")); +#endif if (!d->socketEngine->initialize(socketDescriptor, QAbstractSocket::ListeningState)) { d->serverSocketError = d->socketEngine->error(); d->serverSocketErrorString = d->socketEngine->errorString(); diff --git a/src/network/ssl/qsslsocket.cpp b/src/network/ssl/qsslsocket.cpp index 4252123..39b74d9 100644 --- a/src/network/ssl/qsslsocket.cpp +++ b/src/network/ssl/qsslsocket.cpp @@ -2000,6 +2000,10 @@ void QSslSocketPrivate::createPlainSocket(QIODevice::OpenMode openMode) q->setPeerName(QString()); plainSocket = new QTcpSocket(q); +#ifndef QT_NO_BEARERMANAGEMENT + //copy network session down to the plain socket (if it has been set) + plainSocket->setProperty("_q_networksession", q->property("_q_networksession")); +#endif q->connect(plainSocket, SIGNAL(connected()), q, SLOT(_q_connectedSlot()), Qt::DirectConnection); diff --git a/src/plugins/bearer/symbian/qnetworksession_impl.cpp b/src/plugins/bearer/symbian/qnetworksession_impl.cpp index 2167dbb..e35c01a 100644 --- a/src/plugins/bearer/symbian/qnetworksession_impl.cpp +++ b/src/plugins/bearer/symbian/qnetworksession_impl.cpp @@ -1535,6 +1535,11 @@ bool QNetworkSessionPrivateImpl::easyWlanTrueIapId(TUint32 &trueIapId) const } #endif +RConnection* QNetworkSessionPrivateImpl::nativeSession() +{ + return &iConnection; +} + ConnectionProgressNotifier::ConnectionProgressNotifier(QNetworkSessionPrivateImpl& owner, RConnection& connection) : CActive(CActive::EPriorityUserInput), iOwner(owner), iConnection(connection) { diff --git a/src/plugins/bearer/symbian/qnetworksession_impl.h b/src/plugins/bearer/symbian/qnetworksession_impl.h index a0e7a2a..f2a8a45 100644 --- a/src/plugins/bearer/symbian/qnetworksession_impl.h +++ b/src/plugins/bearer/symbian/qnetworksession_impl.h @@ -111,7 +111,8 @@ public: quint64 bytesWritten() const; quint64 bytesReceived() const; quint64 activeTime() const; - + + RConnection* nativeSession(); #ifdef SNAP_FUNCTIONALITY_AVAILABLE public: // From MMobilityProtocolResp void PreferredCarrierAvailable(TAccessPointInfo aOldAPInfo, diff --git a/tests/auto/qftp/tst_qftp.cpp b/tests/auto/qftp/tst_qftp.cpp index 1b4b503..7e3cd75 100644 --- a/tests/auto/qftp/tst_qftp.cpp +++ b/tests/auto/qftp/tst_qftp.cpp @@ -50,6 +50,10 @@ #include #include #include +#include +#include +#include +#include #include "../network-settings.h" @@ -62,7 +66,9 @@ #define SRCDIR "" #endif - +#ifndef QT_NO_BEARERMANAGEMENT +Q_DECLARE_METATYPE(QNetworkConfiguration) +#endif class tst_QFtp : public QObject { @@ -148,6 +154,10 @@ private: void renameCleanup( const QString &host, const QString &user, const QString &password, const QString &fileToDelete ); QFtp *ftp; +#ifndef QT_NO_BEARERMANAGEMENT + QSharedPointer networkSessionExplicit; + QSharedPointer networkSessionImplicit; +#endif QList ids; // helper to make sure that all expected signals are emitted int current_id; @@ -186,9 +196,9 @@ private: const int bytesTotal_init = -10; const int bytesDone_init = -10; -tst_QFtp::tst_QFtp() +tst_QFtp::tst_QFtp() : + ftp(0) { - Q_SET_DEFAULT_IAP } tst_QFtp::~tst_QFtp() @@ -199,33 +209,62 @@ void tst_QFtp::initTestCase_data() { QTest::addColumn("setProxy"); QTest::addColumn("proxyType"); + QTest::addColumn("setSession"); - QTest::newRow("WithoutProxy") << false << 0; - QTest::newRow("WithSocks5Proxy") << true << int(QNetworkProxy::Socks5Proxy); + QTest::newRow("WithoutProxy") << false << 0 << false; + QTest::newRow("WithSocks5Proxy") << true << int(QNetworkProxy::Socks5Proxy) << false; //### doesn't work well yet. //QTest::newRow("WithHttpProxy") << true << int(QNetworkProxy::HttpProxy); + +#ifndef QT_NO_BEARERMANAGEMENT + QTest::newRow("WithoutProxyWithSession") << false << 0 << true; + QTest::newRow("WithSocks5ProxyAndSession") << true << int(QNetworkProxy::Socks5Proxy) << true; +#endif } void tst_QFtp::initTestCase() { +#ifndef QT_NO_BEARERMANAGEMENT + QNetworkConfigurationManager manager; + networkSessionImplicit = QSharedPointer(new QNetworkSession(manager.defaultConfiguration())); + networkSessionImplicit->open(); + QVERIFY(networkSessionImplicit->waitForOpened(60000)); //there may be user prompt on 1st connect +#endif } void tst_QFtp::cleanupTestCase() { +#ifndef QT_NO_BEARERMANAGEMENT + networkSessionExplicit.clear(); + networkSessionImplicit.clear(); +#endif } void tst_QFtp::init() { QFETCH_GLOBAL(bool, setProxy); + QFETCH_GLOBAL(int, proxyType); + QFETCH_GLOBAL(bool, setSession); if (setProxy) { - QFETCH_GLOBAL(int, proxyType); if (proxyType == QNetworkProxy::Socks5Proxy) { QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::Socks5Proxy, QtNetworkSettings::serverName(), 1080)); } else if (proxyType == QNetworkProxy::HttpProxy) { QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::HttpProxy, QtNetworkSettings::serverName(), 3128)); } } +#ifndef QT_NO_BEARERMANAGEMENT + if (setSession) { + networkSessionExplicit = networkSessionImplicit; + if (!networkSessionExplicit->isOpen()) { + networkSessionExplicit->open(); + QVERIFY(networkSessionExplicit->waitForOpened(30000)); + } + } else { + networkSessionExplicit.clear(); + } +#endif + delete ftp; ftp = 0; ids.clear(); @@ -266,6 +305,12 @@ void tst_QFtp::cleanup() if (setProxy) { QNetworkProxy::setApplicationProxy(QNetworkProxy::DefaultProxy); } + + delete ftp; + ftp = 0; +#ifndef QT_NO_BEARERMANAGEMENT + networkSessionExplicit.clear(); +#endif } void tst_QFtp::connectToHost_data() @@ -289,6 +334,7 @@ void tst_QFtp::connectToHost() QTestEventLoop::instance().enterLoop( 61 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -337,6 +383,7 @@ void tst_QFtp::connectToUnresponsiveHost() QVERIFY( it.value().success == 0 ); delete ftp; + ftp = 0; } void tst_QFtp::login_data() @@ -369,6 +416,7 @@ void tst_QFtp::login() QTestEventLoop::instance().enterLoop( 30 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -415,6 +463,7 @@ void tst_QFtp::close() QTestEventLoop::instance().enterLoop( 30 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -482,6 +531,7 @@ void tst_QFtp::list() QTestEventLoop::instance().enterLoop( 30 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -542,6 +592,7 @@ void tst_QFtp::cd() QTestEventLoop::instance().enterLoop( 30 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) { QFAIL( "Network operation timed out" ); } @@ -617,6 +668,7 @@ void tst_QFtp::get() QTestEventLoop::instance().enterLoop( 50 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -743,6 +795,7 @@ void tst_QFtp::put() break; } delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -775,6 +828,7 @@ void tst_QFtp::put() break; } delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -792,6 +846,7 @@ void tst_QFtp::put() QTestEventLoop::instance().enterLoop( timestep ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -860,6 +915,7 @@ void tst_QFtp::mkdir() QTestEventLoop::instance().enterLoop( 30 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -884,6 +940,7 @@ void tst_QFtp::mkdir() QTestEventLoop::instance().enterLoop( 30 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -903,6 +960,7 @@ void tst_QFtp::mkdir() QTestEventLoop::instance().enterLoop( 30 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -942,6 +1000,7 @@ void tst_QFtp::mkdir2() QVERIFY(commandFinishedSpy.at(3).at(1).toBool()); delete ftp; + ftp = 0; } void tst_QFtp::mkdir2Slot(int id, bool) @@ -1019,6 +1078,7 @@ void tst_QFtp::renameInit( const QString &host, const QString &user, const QStri QTestEventLoop::instance().enterLoop( 50 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -1043,6 +1103,7 @@ void tst_QFtp::renameCleanup( const QString &host, const QString &user, const QS QTestEventLoop::instance().enterLoop( 30 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -1087,6 +1148,7 @@ void tst_QFtp::rename() QTestEventLoop::instance().enterLoop( 30 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -1273,6 +1335,7 @@ void tst_QFtp::commandSequence() QTestEventLoop::instance().enterLoop( 30 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -1330,6 +1393,7 @@ void tst_QFtp::abort() break; } delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -1367,6 +1431,7 @@ void tst_QFtp::abort() QTestEventLoop::instance().enterLoop( 30 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -1425,6 +1490,7 @@ void tst_QFtp::bytesAvailable() ftp->readAll(); QVERIFY( ftp->bytesAvailable() == 0 ); delete ftp; + ftp = 0; } void tst_QFtp::activeMode() @@ -1497,6 +1563,7 @@ void tst_QFtp::proxy() QTestEventLoop::instance().enterLoop( 50 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) { QFAIL( "Network operation timed out" ); } @@ -1512,7 +1579,6 @@ void tst_QFtp::proxy() } } - void tst_QFtp::binaryAscii() { QString file = "asciifile%1.txt"; @@ -1573,6 +1639,7 @@ void tst_QFtp::binaryAscii() QTestEventLoop::instance().enterLoop( 30 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) QFAIL( "Network operation timed out" ); @@ -1868,6 +1935,11 @@ void tst_QFtp::dataTransferProgress( qint64 done, qint64 total ) QFtp *tst_QFtp::newFtp() { QFtp *nFtp = new QFtp( this ); +#ifndef QT_NO_BEARERMANAGEMENT + if (networkSessionExplicit) { + nFtp->setProperty("_q_networksession", QVariant::fromValue(networkSessionExplicit)); + } +#endif connect( nFtp, SIGNAL(commandStarted(int)), SLOT(commandStarted(int)) ); connect( nFtp, SIGNAL(commandFinished(int,bool)), @@ -1920,6 +1992,7 @@ bool tst_QFtp::fileExists( const QString &host, quint16 port, const QString &use inFileDirExistsFunction = TRUE; QTestEventLoop::instance().enterLoop( 30 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) { // ### make this test work qWarning("tst_QFtp::fileExists: Network operation timed out"); @@ -1970,6 +2043,7 @@ bool tst_QFtp::dirExists( const QString &host, quint16 port, const QString &user inFileDirExistsFunction = TRUE; QTestEventLoop::instance().enterLoop( 30 ); delete ftp; + ftp = 0; if ( QTestEventLoop::instance().timeout() ) { // ### make this test work // QFAIL( "Network operation timed out" ); -- cgit v0.12 From 975a51fbe914cf0afd7bde1bf50d1f1f28d12dd7 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Thu, 17 Feb 2011 16:02:55 +0000 Subject: Remove open C setdefaultif support from symbian QNetworkSession Qt no longer uses open C sockets Reviewed-by: Markus Goetz --- .../bearer/symbian/qnetworksession_impl.cpp | 68 +--------------------- src/plugins/bearer/symbian/qnetworksession_impl.h | 3 - 2 files changed, 3 insertions(+), 68 deletions(-) diff --git a/src/plugins/bearer/symbian/qnetworksession_impl.cpp b/src/plugins/bearer/symbian/qnetworksession_impl.cpp index e35c01a..950997f 100644 --- a/src/plugins/bearer/symbian/qnetworksession_impl.cpp +++ b/src/plugins/bearer/symbian/qnetworksession_impl.cpp @@ -45,8 +45,6 @@ #include #include #include -#include -#include #include #ifdef SNAP_FUNCTIONALITY_AVAILABLE @@ -63,29 +61,16 @@ QT_BEGIN_NAMESPACE QNetworkSessionPrivateImpl::QNetworkSessionPrivateImpl(SymbianEngine *engine) : CActive(CActive::EPriorityUserInput), engine(engine), - iDynamicUnSetdefaultif(0), ipConnectionNotifier(0), + iSocketServ(qt_symbianGetSocketServer()), ipConnectionNotifier(0), iHandleStateNotificationsFromManager(false), iFirstSync(true), iStoppedByUser(false), iClosedByUser(false), iError(QNetworkSession::UnknownSessionError), iALREnabled(0), - iConnectInBackground(false), isOpening(false), iSocketServ(qt_symbianGetSocketServer()) + iConnectInBackground(false), isOpening(false) { CActiveScheduler::Add(this); #ifdef SNAP_FUNCTIONALITY_AVAILABLE iMobility = NULL; #endif - // Try to load "Open C" dll dynamically and - // try to attach to unsetdefaultif function dynamically. - // This is to avoid build breaks with old OpenC versions. - if (iOpenCLibrary.Load(_L("libc")) == KErrNone) { - iDynamicUnSetdefaultif = (TOpenCUnSetdefaultifFunction)iOpenCLibrary.Lookup(597); - } -#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG - qDebug() << "QNS this : " << QString::number((uint)this) << " - "; - if (iDynamicUnSetdefaultif) - qDebug() << "dynamic unsetdefaultif() is present in PIPS library. "; - else - qDebug() << "dynamic unsetdefaultif() not present in PIPS library. "; -#endif TRAP_IGNORE(iConnectionMonitor.ConnectL()); } @@ -111,16 +96,12 @@ QNetworkSessionPrivateImpl::~QNetworkSessionPrivateImpl() // Cancel possible RConnection::Start() Cancel(); - // Close global 'Open C' RConnection - // Clears also possible unsetdefaultif() flags. - setdefaultif(0); QSymbianSocketManager::instance().setDefaultConnection(0); iConnectionMonitor.Close(); - iOpenCLibrary.Close(); #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG qDebug() << "QNS this : " << QString::number((uint)this) - << " - destroyed (and setdefaultif(0))"; + << " - destroyed"; #endif } @@ -524,16 +505,6 @@ void QNetworkSessionPrivateImpl::close(bool allowSignals) Cancel(); // closes iConnection - // Close global 'Open C' RConnection. If OpenC supports, - // close the defaultif for good to avoid difficult timing - // and bouncing issues of network going immediately back up - // because of e.g. select() thread etc. - if (iDynamicUnSetdefaultif) { - iDynamicUnSetdefaultif(); - } else { - setdefaultif(0); - } - QSymbianSocketManager::instance().setDefaultConnection(0); // If UserChoice, go down immediately. If some other configuration, // go down immediately if there is no reports expected from the platform; @@ -629,13 +600,6 @@ void QNetworkSessionPrivateImpl::migrate() { #ifdef SNAP_FUNCTIONALITY_AVAILABLE if (iMobility) { - // Close global 'Open C' RConnection. If openC supports, use the 'heavy' - // version to block all subsequent requests. - if (iDynamicUnSetdefaultif) { - iDynamicUnSetdefaultif(); - } else { - setdefaultif(0); - } QSymbianSocketManager::instance().setDefaultConnection(0); // Start migrating to new IAP iMobility->MigrateToPreferredCarrier(); @@ -666,13 +630,6 @@ void QNetworkSessionPrivateImpl::accept() QNetworkConfiguration newActiveConfig = activeConfiguration(iNewRoamingIap); - // Use name of the new IAP to open global 'Open C' RConnection - QByteArray nameAsByteArray = newActiveConfig.name().toUtf8(); - ifreq ifr; - memset(&ifr, 0, sizeof(struct ifreq)); - strcpy(ifr.ifr_name, nameAsByteArray.constData()); - setdefaultif(&ifr); - QSymbianSocketManager::instance().setDefaultConnection(&iConnection); newState(QNetworkSession::Connected, iNewRoamingIap); @@ -691,13 +648,6 @@ void QNetworkSessionPrivateImpl::reject() } else { QNetworkConfiguration newActiveConfig = activeConfiguration(iOldRoamingIap); - // Use name of the old IAP to open global 'Open C' RConnection - QByteArray nameAsByteArray = newActiveConfig.name().toUtf8(); - ifreq ifr; - memset(&ifr, 0, sizeof(struct ifreq)); - strcpy(ifr.ifr_name, nameAsByteArray.constData()); - setdefaultif(&ifr); - QSymbianSocketManager::instance().setDefaultConnection(&iConnection); newState(QNetworkSession::Connected, iOldRoamingIap); @@ -1080,12 +1030,6 @@ void QNetworkSessionPrivateImpl::RunL() // Connectivity Test, ICT, failed). error = KErrGeneral; } else { - // Use name of the IAP to open global 'Open C' RConnection - ifreq ifr; - memset(&ifr, 0, sizeof(struct ifreq)); - QByteArray nameAsByteArray = newActiveConfig.name().toUtf8(); - strcpy(ifr.ifr_name, nameAsByteArray.constData()); - error = setdefaultif(&ifr); QSymbianSocketManager::instance().setDefaultConnection(&iConnection); } if (error != KErrNone) { @@ -1208,12 +1152,6 @@ bool QNetworkSessionPrivateImpl::newState(QNetworkSession::State newState, TUint #endif #ifdef SNAP_FUNCTIONALITY_AVAILABLE - // Use name of the IAP to set default IAP - QByteArray nameAsByteArray = activeConfig.name().toUtf8(); - ifreq ifr; - strcpy(ifr.ifr_name, nameAsByteArray.constData()); - - setdefaultif(&ifr); QSymbianSocketManager::instance().setDefaultConnection(&iConnection); #endif } diff --git a/src/plugins/bearer/symbian/qnetworksession_impl.h b/src/plugins/bearer/symbian/qnetworksession_impl.h index f2a8a45..5aa142f 100644 --- a/src/plugins/bearer/symbian/qnetworksession_impl.h +++ b/src/plugins/bearer/symbian/qnetworksession_impl.h @@ -160,9 +160,6 @@ private: // data QDateTime startTime; - RLibrary iOpenCLibrary; - TOpenCUnSetdefaultifFunction iDynamicUnSetdefaultif; - mutable RSocketServ &iSocketServ; //not owned, shared from QtCore mutable RConnection iConnection; mutable RConnectionMonitor iConnectionMonitor; -- cgit v0.12 From f5e7b6c64caa67bf11fa9754114d686da73b22d6 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 18 Feb 2011 16:47:39 +0000 Subject: Fix RConnection handle leak in symbian bearer plugin The implementation was opening RConnection handles on top of previous instances, and not closing RConnection handles. Both of these cause a resource leak in the socket server which cannot clean up the connection until the Qt process has exited. After a lot of this (which could be triggered by the QNetworkReply auto test), the socket server may run out of memory resulting in all socket operations failing. Reviewed-by: Markus Goetz --- .../bearer/symbian/qnetworksession_impl.cpp | 95 +++++++++------------- src/plugins/bearer/symbian/qnetworksession_impl.h | 1 + 2 files changed, 40 insertions(+), 56 deletions(-) diff --git a/src/plugins/bearer/symbian/qnetworksession_impl.cpp b/src/plugins/bearer/symbian/qnetworksession_impl.cpp index 950997f..760c0e7 100644 --- a/src/plugins/bearer/symbian/qnetworksession_impl.cpp +++ b/src/plugins/bearer/symbian/qnetworksession_impl.cpp @@ -75,32 +75,43 @@ QNetworkSessionPrivateImpl::QNetworkSessionPrivateImpl(SymbianEngine *engine) TRAP_IGNORE(iConnectionMonitor.ConnectL()); } -QNetworkSessionPrivateImpl::~QNetworkSessionPrivateImpl() +void QNetworkSessionPrivateImpl::closeHandles() { - isOpen = false; - isOpening = false; - // Cancel Connection Progress Notifications first. - // Note: ConnectionNotifier must be destroyed before Canceling RConnection::Start() + // Note: ConnectionNotifier must be destroyed before RConnection::Close() // => deleting ipConnectionNotifier results RConnection::CancelProgressNotification() delete ipConnectionNotifier; ipConnectionNotifier = NULL; #ifdef SNAP_FUNCTIONALITY_AVAILABLE - if (iMobility) { - delete iMobility; - iMobility = NULL; - } + // mobility monitor must be deleted before RConnection is closed + delete iMobility; + iMobility = NULL; #endif - // Cancel possible RConnection::Start() + // Cancel possible RConnection::Start() - may call RConnection::Close if Start was in progress Cancel(); + //close any open connection (note Close twice is safe in case Cancel did it above) + iConnection.Close(); QSymbianSocketManager::instance().setDefaultConnection(0); iConnectionMonitor.Close(); #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG qDebug() << "QNS this : " << QString::number((uint)this) + << " - handles closed"; +#endif + +} + +QNetworkSessionPrivateImpl::~QNetworkSessionPrivateImpl() +{ + isOpen = false; + isOpening = false; + + closeHandles(); +#ifdef QT_BEARERMGMT_SYMBIAN_DEBUG + qDebug() << "QNS this : " << QString::number((uint)this) << " - destroyed"; #endif } @@ -148,7 +159,7 @@ void QNetworkSessionPrivateImpl::configurationAdded(QNetworkConfigurationPrivate #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "configurationAdded IAP: " - << toSymbianConfig(privateConfiguration(config))->numericIdentifier(); + << toSymbianConfig(config)->numericIdentifier(); #endif syncStateWithInterface(); @@ -345,6 +356,7 @@ void QNetworkSessionPrivateImpl::open() iStoppedByUser = false; iClosedByUser = false; + Q_ASSERT(!iConnection.SubSessionHandle()); TInt error = iConnection.Open(iSocketServ); if (error != KErrNone) { // Could not open RConnection @@ -385,8 +397,8 @@ void QNetworkSessionPrivateImpl::open() pref.SetIapId(symbianConfig->numericIdentifier()); #endif - iConnection.Start(pref, iStatus); if (!IsActive()) { + iConnection.Start(pref, iStatus); SetActive(); } // Avoid flip flop of states if the configuration is already @@ -413,8 +425,8 @@ void QNetworkSessionPrivateImpl::open() #else TConnSnapPref snapPref(symbianConfig->numericIdentifier()); #endif - iConnection.Start(snapPref, iStatus); if (!IsActive()) { + iConnection.Start(snapPref, iStatus); SetActive(); } // Avoid flip flop of states if the configuration is already @@ -424,8 +436,8 @@ void QNetworkSessionPrivateImpl::open() } } else if (publicConfig.type() == QNetworkConfiguration::UserChoice) { iKnownConfigsBeforeConnectionStart = engine->accessPointConfigurationIdentifiers(); - iConnection.Start(iStatus); if (!IsActive()) { + iConnection.Start(iStatus); SetActive(); } newState(QNetworkSession::Connecting); @@ -436,9 +448,7 @@ void QNetworkSessionPrivateImpl::open() isOpening = false; iError = QNetworkSession::UnknownSessionError; emit QNetworkSessionPrivate::error(iError); - if (ipConnectionNotifier) { - ipConnectionNotifier->StopNotifications(); - } + closeHandles(); syncStateWithInterface(); } } @@ -490,22 +500,11 @@ void QNetworkSessionPrivateImpl::close(bool allowSignals) serviceConfig = QNetworkConfiguration(); -#ifdef SNAP_FUNCTIONALITY_AVAILABLE - if (iMobility) { - delete iMobility; - iMobility = NULL; - } -#endif + closeHandles(); - if (ipConnectionNotifier && !iHandleStateNotificationsFromManager) { - ipConnectionNotifier->StopNotifications(); - // Start handling IAP state change signals from QNetworkConfigurationManagerPrivate - iHandleStateNotificationsFromManager = true; - } - - Cancel(); // closes iConnection + // Start handling IAP state change signals from QNetworkConfigurationManagerPrivate + iHandleStateNotificationsFromManager = true; - QSymbianSocketManager::instance().setDefaultConnection(0); // If UserChoice, go down immediately. If some other configuration, // go down immediately if there is no reports expected from the platform; // in practice Connection Monitor is aware of connections only after @@ -701,12 +700,14 @@ void QNetworkSessionPrivateImpl::NewCarrierActive(TAccessPointInfo /*aNewAPInfo* } } -void QNetworkSessionPrivateImpl::Error(TInt /*aError*/) +void QNetworkSessionPrivateImpl::Error(TInt aError) { #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG qDebug() << "QNS this : " << QString::number((uint)this) << " - " - << "roaming Error() occurred, isOpen is: " << isOpen; + << "roaming Error() occurred" << aError << ", isOpen is: " << isOpen; #endif + if (aError == KErrCancel) + return; //avoid recursive deletion if (isOpen) { isOpen = false; isOpening = false; @@ -714,10 +715,7 @@ void QNetworkSessionPrivateImpl::Error(TInt /*aError*/) serviceConfig = QNetworkConfiguration(); iError = QNetworkSession::RoamingError; emit QNetworkSessionPrivate::error(iError); - Cancel(); - if (ipConnectionNotifier) { - ipConnectionNotifier->StopNotifications(); - } + closeHandles(); QT_TRY { syncStateWithInterface(); // In some cases IAP is still in Connected state when @@ -1037,19 +1035,13 @@ void QNetworkSessionPrivateImpl::RunL() isOpening = false; iError = QNetworkSession::UnknownSessionError; QT_TRYCATCH_LEAVING(emit QNetworkSessionPrivate::error(iError)); - if (ipConnectionNotifier) { - ipConnectionNotifier->StopNotifications(); - } + closeHandles(); if (!newActiveConfig.isValid()) { // No valid configuration, bail out. // Status updates from QNCM won't be received correctly // because there is no configuration to associate them with so transit here. - QSymbianSocketManager::instance().setDefaultConnection(0); - iConnection.Close(); newState(QNetworkSession::Closing); newState(QNetworkSession::Disconnected); - } else { - Cancel(); } QT_TRYCATCH_LEAVING(syncStateWithInterface()); return; @@ -1092,10 +1084,7 @@ void QNetworkSessionPrivateImpl::RunL() serviceConfig = QNetworkConfiguration(); iError = QNetworkSession::InvalidConfigurationError; QT_TRYCATCH_LEAVING(emit QNetworkSessionPrivate::error(iError)); - if (ipConnectionNotifier) { - ipConnectionNotifier->StopNotifications(); - } - Cancel(); + closeHandles(); QT_TRYCATCH_LEAVING(syncStateWithInterface()); break; case KErrCancel: // Connection attempt cancelled @@ -1114,10 +1103,7 @@ void QNetworkSessionPrivateImpl::RunL() iError = QNetworkSession::UnknownSessionError; } QT_TRYCATCH_LEAVING(emit QNetworkSessionPrivate::error(iError)); - if (ipConnectionNotifier) { - ipConnectionNotifier->StopNotifications(); - } - Cancel(); + closeHandles(); QT_TRYCATCH_LEAVING(syncStateWithInterface()); break; } @@ -1204,10 +1190,7 @@ bool QNetworkSessionPrivateImpl::newState(QNetworkSession::State newState, TUint serviceConfig = QNetworkConfiguration(); iError = QNetworkSession::SessionAbortedError; emit QNetworkSessionPrivate::error(iError); - if (ipConnectionNotifier) { - ipConnectionNotifier->StopNotifications(); - } - Cancel(); + closeHandles(); // Start handling IAP state change signals from QNetworkConfigurationManagerPrivate iHandleStateNotificationsFromManager = true; emitSessionClosed = true; // Emit SessionClosed after state change has been reported diff --git a/src/plugins/bearer/symbian/qnetworksession_impl.h b/src/plugins/bearer/symbian/qnetworksession_impl.h index 5aa142f..13980e9 100644 --- a/src/plugins/bearer/symbian/qnetworksession_impl.h +++ b/src/plugins/bearer/symbian/qnetworksession_impl.h @@ -150,6 +150,7 @@ private: bool easyWlanTrueIapId(TUint32 &trueIapId) const; #endif + void closeHandles(); private: // data SymbianEngine *engine; -- cgit v0.12 From 5a6365f14006ab50854e41a5927645c7e9966756 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 18 Feb 2011 17:22:32 +0000 Subject: Refactor dangerous multiple inheritance QObject and CBase both expect to be the root class of the object hierarchy so it can cause problems if they are used in multiple inheritance. Refactored the CActive used for starting RConnection into a helper class. Reviewed-by: Markus Goetz --- .../bearer/symbian/qnetworksession_impl.cpp | 82 ++++++++++++++++------ src/plugins/bearer/symbian/qnetworksession_impl.h | 29 ++++++-- 2 files changed, 86 insertions(+), 25 deletions(-) diff --git a/src/plugins/bearer/symbian/qnetworksession_impl.cpp b/src/plugins/bearer/symbian/qnetworksession_impl.cpp index 760c0e7..5325293 100644 --- a/src/plugins/bearer/symbian/qnetworksession_impl.cpp +++ b/src/plugins/bearer/symbian/qnetworksession_impl.cpp @@ -60,13 +60,12 @@ QT_BEGIN_NAMESPACE QNetworkSessionPrivateImpl::QNetworkSessionPrivateImpl(SymbianEngine *engine) -: CActive(CActive::EPriorityUserInput), engine(engine), - iSocketServ(qt_symbianGetSocketServer()), ipConnectionNotifier(0), +: engine(engine), iSocketServ(qt_symbianGetSocketServer()), + ipConnectionNotifier(0), ipConnectionStarter(0), iHandleStateNotificationsFromManager(false), iFirstSync(true), iStoppedByUser(false), iClosedByUser(false), iError(QNetworkSession::UnknownSessionError), iALREnabled(0), iConnectInBackground(false), isOpening(false) { - CActiveScheduler::Add(this); #ifdef SNAP_FUNCTIONALITY_AVAILABLE iMobility = NULL; @@ -90,7 +89,8 @@ void QNetworkSessionPrivateImpl::closeHandles() #endif // Cancel possible RConnection::Start() - may call RConnection::Close if Start was in progress - Cancel(); + delete ipConnectionStarter; + ipConnectionStarter = 0; //close any open connection (note Close twice is safe in case Cancel did it above) iConnection.Close(); @@ -397,9 +397,9 @@ void QNetworkSessionPrivateImpl::open() pref.SetIapId(symbianConfig->numericIdentifier()); #endif - if (!IsActive()) { - iConnection.Start(pref, iStatus); - SetActive(); + if (!ipConnectionStarter) { + ipConnectionStarter = new ConnectionStarter(*this, iConnection); + ipConnectionStarter->Start(pref); } // Avoid flip flop of states if the configuration is already // active. IsOpen/opened() will indicate when ready. @@ -425,9 +425,9 @@ void QNetworkSessionPrivateImpl::open() #else TConnSnapPref snapPref(symbianConfig->numericIdentifier()); #endif - if (!IsActive()) { - iConnection.Start(snapPref, iStatus); - SetActive(); + if (!ipConnectionStarter) { + ipConnectionStarter = new ConnectionStarter(*this, iConnection); + ipConnectionStarter->Start(snapPref); } // Avoid flip flop of states if the configuration is already // active. IsOpen/opened() will indicate when ready. @@ -436,9 +436,9 @@ void QNetworkSessionPrivateImpl::open() } } else if (publicConfig.type() == QNetworkConfiguration::UserChoice) { iKnownConfigsBeforeConnectionStart = engine->accessPointConfigurationIdentifiers(); - if (!IsActive()) { - iConnection.Start(iStatus); - SetActive(); + if (!ipConnectionStarter) { + ipConnectionStarter = new ConnectionStarter(*this, iConnection); + ipConnectionStarter->Start(); } newState(QNetworkSession::Connecting); } @@ -1007,13 +1007,14 @@ QNetworkConfiguration QNetworkSessionPrivateImpl::activeConfiguration(TUint32 ia return publicConfig; } -void QNetworkSessionPrivateImpl::RunL() +void QNetworkSessionPrivateImpl::ConnectionStartComplete(TInt statusCode) { #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG qDebug() << "QNS this : " << QString::number((uint)this) << " - " - << "RConnection::RunL with status code: " << iStatus.Int(); + << "RConnection::Start completed with status code: " << statusCode; #endif - TInt statusCode = iStatus.Int(); + delete ipConnectionStarter; + ipConnectionStarter = 0; switch (statusCode) { case KErrNone: // Connection created successfully @@ -1109,11 +1110,6 @@ void QNetworkSessionPrivateImpl::RunL() } } -void QNetworkSessionPrivateImpl::DoCancel() -{ - iConnection.Close(); -} - // Enters newState if feasible according to current state. // AccessPointId may be given as parameter. If it is zero, state-change is assumed to // concern this session's configuration. If non-zero, the configuration is looked up @@ -1500,6 +1496,50 @@ void ConnectionProgressNotifier::RunL() } } +ConnectionStarter::ConnectionStarter(QNetworkSessionPrivateImpl &owner, RConnection &connection) + : CActive(CActive::EPriorityUserInput), iOwner(owner), iConnection(connection) +{ + CActiveScheduler::Add(this); +} + +ConnectionStarter::~ConnectionStarter() +{ + Cancel(); +} + +void ConnectionStarter::Start() +{ + if (!IsActive()) { + iConnection.Start(iStatus); + SetActive(); + } +} + +void ConnectionStarter::Start(TConnPref &pref) +{ + if (!IsActive()) { + iConnection.Start(pref, iStatus); + SetActive(); + } +} + +void ConnectionStarter::RunL() +{ + iOwner.ConnectionStartComplete(iStatus.Int()); + //note owner deletes on callback +} + +TInt ConnectionStarter::RunError(TInt err) +{ + qWarning() << "ConnectionStarter::RunError" << err; + return KErrNone; +} + +void ConnectionStarter::DoCancel() +{ + iConnection.Close(); +} + QT_END_NAMESPACE #endif //QT_NO_BEARERMANAGEMENT diff --git a/src/plugins/bearer/symbian/qnetworksession_impl.h b/src/plugins/bearer/symbian/qnetworksession_impl.h index 13980e9..2dda456 100644 --- a/src/plugins/bearer/symbian/qnetworksession_impl.h +++ b/src/plugins/bearer/symbian/qnetworksession_impl.h @@ -68,11 +68,12 @@ QT_BEGIN_NAMESPACE class ConnectionProgressNotifier; +class ConnectionStarter; class SymbianEngine; typedef void (*TOpenCUnSetdefaultifFunction)(); -class QNetworkSessionPrivateImpl : public QNetworkSessionPrivate, public CActive +class QNetworkSessionPrivateImpl : public QNetworkSessionPrivate #ifdef SNAP_FUNCTIONALITY_AVAILABLE , public MMobilityProtocolResp #endif @@ -126,7 +127,7 @@ public: // From MMobilityProtocolResp #endif protected: // From CActive - void RunL(); + void ConnectionStartComplete(TInt statusCode); void DoCancel(); private Q_SLOTS: @@ -165,12 +166,13 @@ private: // data mutable RConnection iConnection; mutable RConnectionMonitor iConnectionMonitor; ConnectionProgressNotifier* ipConnectionNotifier; - + ConnectionStarter* ipConnectionStarter; + bool iHandleStateNotificationsFromManager; bool iFirstSync; bool iStoppedByUser; bool iClosedByUser; - + #ifdef SNAP_FUNCTIONALITY_AVAILABLE CActiveCommsMobilityApiExt* iMobility; #endif @@ -188,6 +190,7 @@ private: // data bool isOpening; friend class ConnectionProgressNotifier; + friend class ConnectionStarter; }; class ConnectionProgressNotifier : public CActive @@ -210,6 +213,24 @@ private: // Data }; +class ConnectionStarter : public CActive +{ +public: + ConnectionStarter(QNetworkSessionPrivateImpl &owner, RConnection &connection); + ~ConnectionStarter(); + + void Start(); + void Start(TConnPref &pref); +protected: + void RunL(); + TInt RunError(TInt err); + void DoCancel(); + +private: // Data + QNetworkSessionPrivateImpl &iOwner; + RConnection& iConnection; +}; + QT_END_NAMESPACE #endif //QNETWORKSESSION_IMPL_H -- cgit v0.12 From b2c41f756e1c0abd3f07a2e7256c3ba1be72832a Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 21 Feb 2011 10:39:28 +0000 Subject: Implement network session for HTTP backend Reviewed-by: Markus Goetz --- src/network/access/qhttpnetworkconnection.cpp | 23 ++++++++++++++++++++++ src/network/access/qhttpnetworkconnection_p.h | 10 ++++++++++ .../access/qhttpnetworkconnectionchannel.cpp | 9 +++++++++ .../access/qhttpnetworkconnectionchannel_p.h | 3 +++ 4 files changed, 45 insertions(+) diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp index e94b099..08a8016 100644 --- a/src/network/access/qhttpnetworkconnection.cpp +++ b/src/network/access/qhttpnetworkconnection.cpp @@ -117,9 +117,14 @@ QHttpNetworkConnectionPrivate::~QHttpNetworkConnectionPrivate() void QHttpNetworkConnectionPrivate::init() { + Q_Q(QHttpNetworkConnection); for (int i = 0; i < channelCount; i++) { channels[i].setConnection(this->q_func()); channels[i].ssl = encrypt; +#ifndef QT_NO_BEARERMANAGEMENT + //push session down to channels + channels[i].networkSession = networkSession; +#endif channels[i].init(); } } @@ -819,6 +824,23 @@ void QHttpNetworkConnectionPrivate::readMoreLater(QHttpNetworkReply *reply) } } +#ifndef QT_NO_BEARERMANAGEMENT +QHttpNetworkConnection::QHttpNetworkConnection(const QString &hostName, quint16 port, bool encrypt, QObject *parent, QSharedPointer networkSession) + : QObject(*(new QHttpNetworkConnectionPrivate(hostName, port, encrypt)), parent) +{ + Q_D(QHttpNetworkConnection); + d->networkSession = networkSession; + d->init(); +} + +QHttpNetworkConnection::QHttpNetworkConnection(quint16 connectionCount, const QString &hostName, quint16 port, bool encrypt, QObject *parent, QSharedPointer networkSession) + : QObject(*(new QHttpNetworkConnectionPrivate(connectionCount, hostName, port, encrypt)), parent) +{ + Q_D(QHttpNetworkConnection); + d->networkSession = networkSession; + d->init(); +} +#else QHttpNetworkConnection::QHttpNetworkConnection(const QString &hostName, quint16 port, bool encrypt, QObject *parent) : QObject(*(new QHttpNetworkConnectionPrivate(hostName, port, encrypt)), parent) { @@ -832,6 +854,7 @@ QHttpNetworkConnection::QHttpNetworkConnection(quint16 connectionCount, const QS Q_D(QHttpNetworkConnection); d->init(); } +#endif QHttpNetworkConnection::~QHttpNetworkConnection() { diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h index d4748c1..ad53dec 100644 --- a/src/network/access/qhttpnetworkconnection_p.h +++ b/src/network/access/qhttpnetworkconnection_p.h @@ -55,6 +55,7 @@ #include #include #include +#include #include #include @@ -88,8 +89,13 @@ class Q_AUTOTEST_EXPORT QHttpNetworkConnection : public QObject Q_OBJECT public: +#ifndef QT_NO_BEARERMANAGEMENT + QHttpNetworkConnection(const QString &hostName, quint16 port = 80, bool encrypt = false, QObject *parent = 0, QSharedPointer networkSession = QSharedPointer()); + QHttpNetworkConnection(quint16 channelCount, const QString &hostName, quint16 port = 80, bool encrypt = false, QObject *parent = 0, QSharedPointer networkSession = QSharedPointer()); +#else QHttpNetworkConnection(const QString &hostName, quint16 port = 80, bool encrypt = false, QObject *parent = 0); QHttpNetworkConnection(quint16 channelCount, const QString &hostName, quint16 port = 80, bool encrypt = false, QObject *parent = 0); +#endif ~QHttpNetworkConnection(); //The hostname to which this is connected to. @@ -208,6 +214,10 @@ public: QList highPriorityQueue; QList lowPriorityQueue; +#ifndef QT_NO_BEARERMANAGEMENT + QSharedPointer networkSession; +#endif + friend class QHttpNetworkConnectionChannel; }; diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index 079f608..3aaa11d 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -54,6 +54,10 @@ # include #endif +#ifndef QT_NO_BEARERMANAGEMENT +#include "private/qnetworksession_p.h" +#endif + QT_BEGIN_NAMESPACE // TODO: Put channel specific stuff here so it does not polute qhttpnetworkconnection.cpp @@ -91,6 +95,11 @@ void QHttpNetworkConnectionChannel::init() #else socket = new QTcpSocket; #endif +#ifndef QT_NO_BEARERMANAGEMENT + //push session down to socket + if (networkSession) + socket->setProperty("_q_networksession", QVariant::fromValue(networkSession)); +#endif // Set by QNAM anyway, but let's be safe here socket->setProxy(QNetworkProxy::NoProxy); diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h index 8cbc689..d86f95f 100644 --- a/src/network/access/qhttpnetworkconnectionchannel_p.h +++ b/src/network/access/qhttpnetworkconnectionchannel_p.h @@ -116,6 +116,9 @@ public: bool ignoreAllSslErrors; QList ignoreSslErrorsList; #endif +#ifndef QT_NO_BEARERMANAGEMENT + QSharedPointer networkSession; +#endif // HTTP pipelining -> http://en.wikipedia.org/wiki/Http_pipelining enum PipeliningSupport { -- cgit v0.12 From 7f41f062e05c02ddf31ab6b81444f57904614f2a Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 22 Feb 2011 15:40:19 +0000 Subject: Fix duplicate calls to _q_startOperation Because of the shared QNetworkSession, we need to disconnect the signals before detaching from the session. Otherwise we may receive signals from an old session after switching configurations. Also, when a session is connected, we get both the state change (connected) and the opened signals from the session. This needs to be distinguished from the roaming->connected state change to avoid getting the networkSessionConnected signal twice. Reviewed-by: Markus Goetz Task-Number: QTBUG-16901 --- src/network/access/qnetworkaccessmanager.cpp | 36 ++++++++++++++++++++++++---- src/network/access/qnetworkaccessmanager_p.h | 2 ++ src/network/access/qnetworkreplyimpl.cpp | 2 +- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index f1c4447..00c5d26 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -1344,8 +1344,25 @@ void QNetworkAccessManagerPrivate::createSession(const QNetworkConfiguration &co initializeSession = false; - if (!config.isValid()) { - networkSession.clear(); + QSharedPointer newSession; + if (config.isValid()) + newSession = QSharedNetworkSessionManager::getSession(config); + + if (networkSession) { + //do nothing if new and old session are the same + if (networkSession == newSession) + return; + //disconnect from old session + QObject::disconnect(networkSession.data(), SIGNAL(opened()), q, SIGNAL(networkSessionConnected())); + QObject::disconnect(networkSession.data(), SIGNAL(closed()), q, SLOT(_q_networkSessionClosed())); + QObject::disconnect(networkSession.data(), SIGNAL(stateChanged(QNetworkSession::State)), + q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State))); + } + + //switch to new session (null if config was invalid) + networkSession = newSession; + + if (!networkSession) { online = false; if (networkAccessible == QNetworkAccessManager::NotAccessible) @@ -1356,8 +1373,7 @@ void QNetworkAccessManagerPrivate::createSession(const QNetworkConfiguration &co return; } - networkSession = QSharedNetworkSessionManager::getSession(config); - + //connect to new session QObject::connect(networkSession.data(), SIGNAL(opened()), q, SIGNAL(networkSessionConnected()), Qt::QueuedConnection); //QueuedConnection is used to avoid deleting the networkSession inside its closed signal QObject::connect(networkSession.data(), SIGNAL(closed()), q, SLOT(_q_networkSessionClosed()), Qt::QueuedConnection); @@ -1369,9 +1385,15 @@ void QNetworkAccessManagerPrivate::createSession(const QNetworkConfiguration &co void QNetworkAccessManagerPrivate::_q_networkSessionClosed() { + Q_Q(QNetworkAccessManager); if (networkSession) { networkConfiguration = networkSession->configuration().identifier(); + //disconnect from old session + QObject::disconnect(networkSession.data(), SIGNAL(opened()), q, SIGNAL(networkSessionConnected())); + QObject::disconnect(networkSession.data(), SIGNAL(closed()), q, SLOT(_q_networkSessionClosed())); + QObject::disconnect(networkSession.data(), SIGNAL(stateChanged(QNetworkSession::State)), + q, SLOT(_q_networkSessionStateChanged(QNetworkSession::State))); networkSession.clear(); } } @@ -1380,8 +1402,12 @@ void QNetworkAccessManagerPrivate::_q_networkSessionStateChanged(QNetworkSession { Q_Q(QNetworkAccessManager); - if (state == QNetworkSession::Connected) + //Do not emit the networkSessionConnected signal here, except for roaming -> connected + //transition, otherwise it is emitted twice in a row when opening a connection. + if (state == QNetworkSession::Connected && lastSessionState == QNetworkSession::Roaming) emit q->networkSessionConnected(); + lastSessionState = state; + if (online) { if (state != QNetworkSession::Connected && state != QNetworkSession::Roaming) { online = false; diff --git a/src/network/access/qnetworkaccessmanager_p.h b/src/network/access/qnetworkaccessmanager_p.h index cf4d2f3..6dcb6da 100644 --- a/src/network/access/qnetworkaccessmanager_p.h +++ b/src/network/access/qnetworkaccessmanager_p.h @@ -77,6 +77,7 @@ public: #endif #ifndef QT_NO_BEARERMANAGEMENT networkSession(0), + lastSessionState(QNetworkSession::Invalid), networkAccessible(QNetworkAccessManager::Accessible), online(false), initializeSession(true), @@ -129,6 +130,7 @@ public: #ifndef QT_NO_BEARERMANAGEMENT QSharedPointer networkSession; + QNetworkSession::State lastSessionState; QString networkConfiguration; QNetworkAccessManager::NetworkAccessibility networkAccessible; bool online; diff --git a/src/network/access/qnetworkreplyimpl.cpp b/src/network/access/qnetworkreplyimpl.cpp index 41a6c62..8f2e64e 100644 --- a/src/network/access/qnetworkreplyimpl.cpp +++ b/src/network/access/qnetworkreplyimpl.cpp @@ -74,7 +74,7 @@ inline QNetworkReplyImplPrivate::QNetworkReplyImplPrivate() void QNetworkReplyImplPrivate::_q_startOperation() { // ensure this function is only being called once - if (state == Working) { + if (state == Working || state == Finished) { qDebug("QNetworkReplyImpl::_q_startOperation was called more than once"); return; } -- cgit v0.12 From b7667461ca80613d018f2258b54b5d1f9195e50d Mon Sep 17 00:00:00 2001 From: Martin Petersson Date: Tue, 22 Feb 2011 17:12:40 +0100 Subject: tst_qnetworkreply: Fix httpProxyCommands() on Windows. Reviewed-by: Markus Goetz --- src/network/socket/qhttpsocketengine.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/network/socket/qhttpsocketengine.cpp b/src/network/socket/qhttpsocketengine.cpp index 4e628f3..6a025f2 100644 --- a/src/network/socket/qhttpsocketengine.cpp +++ b/src/network/socket/qhttpsocketengine.cpp @@ -743,7 +743,10 @@ void QHttpSocketEngine::emitReadNotification() { Q_D(QHttpSocketEngine); d->readNotificationActivated = true; - if (d->readNotificationEnabled && !d->readNotificationPending) { + // if there is a connection notification pending we have to emit the readNotification + // incase there is connection error. This is only needed for Windows, but it does not + // hurt in other cases. + if ((d->readNotificationEnabled && !d->readNotificationPending) || d->connectionNotificationPending) { d->readNotificationPending = true; QMetaObject::invokeMethod(this, "emitPendingReadNotification", Qt::QueuedConnection); } -- cgit v0.12 From d9753717f322ffdd59017e91541fe27201940169 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Wed, 23 Feb 2011 13:52:29 +0000 Subject: Fix compile errors in bearer tests Excluded maemo code from symbian builds. Reviewed-by: Markus Goetz --- tests/auto/qnetworkconfiguration/tst_qnetworkconfiguration.cpp | 8 ++++---- .../tst_qnetworkconfigurationmanager.cpp | 8 ++++---- tests/auto/qnetworksession/test/tst_qnetworksession.cpp | 10 ++++------ 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/tests/auto/qnetworkconfiguration/tst_qnetworkconfiguration.cpp b/tests/auto/qnetworkconfiguration/tst_qnetworkconfiguration.cpp index adcfd93..c31eac7 100644 --- a/tests/auto/qnetworkconfiguration/tst_qnetworkconfiguration.cpp +++ b/tests/auto/qnetworkconfiguration/tst_qnetworkconfiguration.cpp @@ -52,7 +52,7 @@ */ #include -#if defined(Q_OS_UNIX) && !defined(QT_NO_ICD) +#if defined(Q_OS_UNIX) && !defined(QT_NO_ICD) && !defined (Q_OS_SYMBIAN) #include #include #endif @@ -73,7 +73,7 @@ private slots: void isRoamingAvailable(); private: -#if defined(Q_OS_UNIX) && !defined(QT_NO_ICD) +#if defined(Q_OS_UNIX) && !defined(QT_NO_ICD) && !defined (Q_OS_SYMBIAN) Maemo::IAPConf *iapconf; Maemo::IAPConf *iapconf2; Maemo::IAPConf *gprsiap; @@ -85,7 +85,7 @@ private: void tst_QNetworkConfiguration::initTestCase() { -#if defined(Q_OS_UNIX) && !defined(QT_NO_ICD) +#if defined(Q_OS_UNIX) && !defined(QT_NO_ICD) && !defined (Q_OS_SYMBIAN) iapconf = new Maemo::IAPConf("007"); iapconf->setValue("ipv4_type", "AUTO"); iapconf->setValue("wlan_wepkey1", "connt"); @@ -158,7 +158,7 @@ void tst_QNetworkConfiguration::initTestCase() void tst_QNetworkConfiguration::cleanupTestCase() { -#if defined(Q_OS_UNIX) && !defined(QT_NO_ICD) +#if defined(Q_OS_UNIX) && !defined(QT_NO_ICD) && !defined (Q_OS_SYMBIAN) iapconf->clear(); delete iapconf; iapconf2->clear(); diff --git a/tests/auto/qnetworkconfigurationmanager/tst_qnetworkconfigurationmanager.cpp b/tests/auto/qnetworkconfigurationmanager/tst_qnetworkconfigurationmanager.cpp index 443fd18..7787608 100644 --- a/tests/auto/qnetworkconfigurationmanager/tst_qnetworkconfigurationmanager.cpp +++ b/tests/auto/qnetworkconfigurationmanager/tst_qnetworkconfigurationmanager.cpp @@ -45,7 +45,7 @@ #include #include -#if defined(Q_OS_UNIX) && !defined(QT_NO_ICD) +#if defined(Q_OS_UNIX) && !defined(QT_NO_ICD) && !defined (Q_OS_SYMBIAN) #include #include #endif @@ -67,7 +67,7 @@ private slots: void configurationFromIdentifier(); private: -#if defined(Q_OS_UNIX) && !defined(QT_NO_ICD) +#if defined(Q_OS_UNIX) && !defined(QT_NO_ICD) && !defined (Q_OS_SYMBIAN) Maemo::IAPConf *iapconf; Maemo::IAPConf *iapconf2; Maemo::IAPConf *gprsiap; @@ -79,7 +79,7 @@ private: void tst_QNetworkConfigurationManager::initTestCase() { -#if defined(Q_OS_UNIX) && !defined(QT_NO_ICD) +#if defined(Q_OS_UNIX) && !defined(QT_NO_ICD) && !defined (Q_OS_SYMBIAN) iapconf = new Maemo::IAPConf("007"); iapconf->setValue("ipv4_type", "AUTO"); iapconf->setValue("wlan_wepkey1", "connt"); @@ -153,7 +153,7 @@ void tst_QNetworkConfigurationManager::initTestCase() void tst_QNetworkConfigurationManager::cleanupTestCase() { -#if defined(Q_OS_UNIX) && !defined(QT_NO_ICD) +#if defined(Q_OS_UNIX) && !defined(QT_NO_ICD) && !defined (Q_OS_SYMBIAN) iapconf->clear(); delete iapconf; iapconf2->clear(); diff --git a/tests/auto/qnetworksession/test/tst_qnetworksession.cpp b/tests/auto/qnetworksession/test/tst_qnetworksession.cpp index 37fc9cd..154f790 100644 --- a/tests/auto/qnetworksession/test/tst_qnetworksession.cpp +++ b/tests/auto/qnetworksession/test/tst_qnetworksession.cpp @@ -48,7 +48,7 @@ #include #include -#if defined(Q_OS_UNIX) && !defined(QT_NO_ICD) +#if defined(Q_OS_UNIX) && !defined(QT_NO_ICD) && !defined (Q_OS_SYMBIAN) #include #include #endif @@ -60,8 +60,6 @@ QT_USE_NAMESPACE Q_DECLARE_METATYPE(QNetworkConfiguration) Q_DECLARE_METATYPE(QNetworkConfiguration::Type); -Q_DECLARE_METATYPE(QNetworkSession::State); -Q_DECLARE_METATYPE(QNetworkSession::SessionError); class tst_QNetworkSession : public QObject { @@ -107,7 +105,7 @@ private: int inProcessSessionManagementCount; -#if defined(Q_OS_UNIX) && !defined(QT_NO_ICD) +#if defined(Q_OS_UNIX) && !defined(QT_NO_ICD) && !defined (Q_OS_SYMBIAN) Maemo::IAPConf *iapconf; Maemo::IAPConf *iapconf2; Maemo::IAPConf *gprsiap; @@ -144,7 +142,7 @@ void tst_QNetworkSession::initTestCase() testsToRun["userChoiceSession"] = true; testsToRun["sessionOpenCloseStop"] = true; -#if defined(Q_OS_UNIX) && !defined(QT_NO_ICD) +#if defined(Q_OS_UNIX) && !defined(QT_NO_ICD) && !defined (Q_OS_SYMBIAN) iapconf = new Maemo::IAPConf("007"); iapconf->setValue("ipv4_type", "AUTO"); iapconf->setValue("wlan_wepkey1", "connt"); @@ -230,7 +228,7 @@ void tst_QNetworkSession::cleanupTestCase() "inProcessSessionManagement()"); } -#if defined(Q_OS_UNIX) && !defined(QT_NO_ICD) +#if defined(Q_OS_UNIX) && !defined(QT_NO_ICD) && !defined (Q_OS_SYMBIAN) iapconf->clear(); delete iapconf; iapconf2->clear(); -- cgit v0.12 From dc01a7829255a41bda606fb59f546d599b6654ba Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Wed, 23 Feb 2011 14:36:07 +0000 Subject: Fix ignored messages in platformsocketengine test Reviewed-by: Markus Goetz --- tests/auto/platformsocketengine/tst_platformsocketengine.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/auto/platformsocketengine/tst_platformsocketengine.cpp b/tests/auto/platformsocketengine/tst_platformsocketengine.cpp index 0ecb4ae..184371d 100644 --- a/tests/auto/platformsocketengine/tst_platformsocketengine.cpp +++ b/tests/auto/platformsocketengine/tst_platformsocketengine.cpp @@ -68,10 +68,12 @@ #include #include #define PLATFORMSOCKETENGINE QSymbianSocketEngine +#define PLATFORMSOCKETENGINESTRING "QSymbianSocketEngine" #include #include #else #define PLATFORMSOCKETENGINE QNativeSocketEngine +#define PLATFORMSOCKETENGINESTRING "QNativeSocketEngine" #include #endif @@ -148,10 +150,10 @@ void tst_PlatformSocketEngine::construction() QVERIFY(socketDevice.peerPort() == 0); QVERIFY(socketDevice.error() == QAbstractSocket::UnknownSocketError); - QTest::ignoreMessage(QtWarningMsg, "QNativeSocketEngine::bytesAvailable() was called in QAbstractSocket::UnconnectedState"); + QTest::ignoreMessage(QtWarningMsg, PLATFORMSOCKETENGINESTRING "::bytesAvailable() was called in QAbstractSocket::UnconnectedState"); QVERIFY(socketDevice.bytesAvailable() == 0); - QTest::ignoreMessage(QtWarningMsg, "QNativeSocketEngine::hasPendingDatagrams() was called in QAbstractSocket::UnconnectedState"); + QTest::ignoreMessage(QtWarningMsg, PLATFORMSOCKETENGINESTRING "::hasPendingDatagrams() was called in QAbstractSocket::UnconnectedState"); QVERIFY(!socketDevice.hasPendingDatagrams()); } @@ -664,7 +666,7 @@ void tst_PlatformSocketEngine::invalidSend() PLATFORMSOCKETENGINE socket; QVERIFY(socket.initialize(QAbstractSocket::TcpSocket)); - QTest::ignoreMessage(QtWarningMsg, "QNativeSocketEngine::writeDatagram() was" + QTest::ignoreMessage(QtWarningMsg, PLATFORMSOCKETENGINESTRING "::writeDatagram() was" " called by a socket other than QAbstractSocket::UdpSocket"); QCOMPARE(socket.writeDatagram("hei", 3, QHostAddress::LocalHost, 143), (qlonglong) -1); -- cgit v0.12 From 8d1ee3335f4c1bf262fb3a85fd4cc7e837129b8c Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Wed, 23 Feb 2011 15:28:54 +0000 Subject: bugfix: QDir::entryList(Files|Readable) not listing writable files Mistake in the qfilesystemiterator_symbian implementation. Readable without Writable was thought to mean show only read-only files, but this isn't the expected behaviour of QDir[Iterator] Added an autotest, as this was only covered by ssl tests in the network layer. Reviewed-by: joao --- src/corelib/io/qfilesystemiterator_symbian.cpp | 2 -- tests/auto/qdir/tst_qdir.cpp | 6 ++++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/corelib/io/qfilesystemiterator_symbian.cpp b/src/corelib/io/qfilesystemiterator_symbian.cpp index e316526..0adc26d 100644 --- a/src/corelib/io/qfilesystemiterator_symbian.cpp +++ b/src/corelib/io/qfilesystemiterator_symbian.cpp @@ -88,8 +88,6 @@ QFileSystemIterator::QFileSystemIterator(const QFileSystemEntry &path, QDir::Fil else if (symbianMask == 0) { if ((filters & QDir::PermissionMask) == QDir::Writable) symbianMask = KEntryAttMatchExclude | KEntryAttReadOnly; - else if ((filters & QDir::PermissionMask) == QDir::Readable) - symbianMask = KEntryAttMatchExclusive | KEntryAttReadOnly; } lastError = dirHandle.Open(fs, qt_QString2TPtrC(absPath), symbianMask); diff --git a/tests/auto/qdir/tst_qdir.cpp b/tests/auto/qdir/tst_qdir.cpp index 2fa0c24..21460be 100644 --- a/tests/auto/qdir/tst_qdir.cpp +++ b/tests/auto/qdir/tst_qdir.cpp @@ -571,6 +571,12 @@ void tst_QDir::entryList_data() << int(QDir::AllEntries | QDir::Writable) << int(QDir::Name) << filterLinks(QString(".,..,directory,linktodirectory.lnk,writable").split(',')); #endif + QTest::newRow("QDir::Files | QDir::Readable") << SRCDIR "entrylist/" << QStringList("*") + << int(QDir::Files | QDir::Readable) << int(QDir::Name) + << filterLinks(QString("file,linktofile.lnk,writable").split(',')); + QTest::newRow("QDir::Dirs | QDir::Readable") << SRCDIR "entrylist/" << QStringList("*") + << int(QDir::Dirs | QDir::Readable) << int(QDir::Name) + << filterLinks(QString(".,..,directory,linktodirectory.lnk").split(',')); QTest::newRow("Namefilters b*") << SRCDIR "entrylist/" << QStringList("d*") << int(QDir::NoFilter) << int(QDir::Name) << filterLinks(QString("directory").split(',')); -- cgit v0.12 From 6a8a70b434c61bc39e4aad0036012e78fa690b1d Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Wed, 23 Feb 2011 17:12:44 +0000 Subject: Fix qsslsocket test crashes Convert assertions to failure, increase heap size to allow creating 10MB buffers without std::bad_alloc exception or memory allocation error from openssl. Reviewed-by: Markus Goetz --- tests/auto/qsslsocket/qsslsocket.pro | 2 +- tests/auto/qsslsocket/tst_qsslsocket.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/auto/qsslsocket/qsslsocket.pro b/tests/auto/qsslsocket/qsslsocket.pro index aeeae8f..154f9ca 100644 --- a/tests/auto/qsslsocket/qsslsocket.pro +++ b/tests/auto/qsslsocket/qsslsocket.pro @@ -23,7 +23,7 @@ wince* { DEPLOYMENT += certFiles } else:symbian { DEFINES += QSSLSOCKET_CERTUNTRUSTED_WORKAROUND - TARGET.EPOCHEAPSIZE="0x100 0x1000000" + TARGET.EPOCHEAPSIZE="0x100 0x3000000" TARGET.CAPABILITY=NetworkServices certFiles.files = certs ssl.tar.gz diff --git a/tests/auto/qsslsocket/tst_qsslsocket.cpp b/tests/auto/qsslsocket/tst_qsslsocket.cpp index 8177d29..9a98712 100644 --- a/tests/auto/qsslsocket/tst_qsslsocket.cpp +++ b/tests/auto/qsslsocket/tst_qsslsocket.cpp @@ -541,7 +541,7 @@ void tst_QSslSocket::sslErrors() } #ifdef QSSLSOCKET_CERTUNTRUSTED_WORKAROUND - if (output.last() == QSslError::CertificateUntrusted) + if (output.count() && output.last() == QSslError::CertificateUntrusted) output.takeLast(); #endif QCOMPARE(output, expected); @@ -1417,8 +1417,8 @@ protected: // delayed start of encryption QTest::qSleep(100); QSslSocket *socket = server.socket; - Q_ASSERT(socket); - Q_ASSERT(socket->isValid()); + QVERIFY(socket); + QVERIFY(socket->isValid()); socket->ignoreSslErrors(); socket->startServerEncryption(); if (!socket->waitForEncrypted(2000)) -- cgit v0.12 From 88e192419ed928be1239d7a928336332f1d521f4 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Wed, 23 Feb 2011 18:20:14 +0000 Subject: Fix symbian test failures for qsslsocket Increased timeout on some unstable test cases. Added a Q_EXPECT_FAIL if we can't connect to a server which is inside firewall. Reviewed-by: Markus Goetz --- tests/auto/qsslsocket/tst_qsslsocket.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/auto/qsslsocket/tst_qsslsocket.cpp b/tests/auto/qsslsocket/tst_qsslsocket.cpp index 9a98712..1c34759 100644 --- a/tests/auto/qsslsocket/tst_qsslsocket.cpp +++ b/tests/auto/qsslsocket/tst_qsslsocket.cpp @@ -519,6 +519,7 @@ void tst_QSslSocket::sslErrors_data() << (SslErrorList() << QSslError::HostNameMismatch << QSslError::SelfSignedCertificate); + //note this test case does not work outside Nokia network QTest::newRow("imap.trolltech.com") << "imap.trolltech.com" << 993 @@ -533,6 +534,8 @@ void tst_QSslSocket::sslErrors() QSslSocketPtr socket = newSocket(); socket->connectToHostEncrypted(host, port); + if (!socket->waitForConnected()) + QEXPECT_FAIL("imap.trolltech.com", "server not open to internet", Continue); socket->waitForEncrypted(5000); SslErrorList output; @@ -650,7 +653,7 @@ void tst_QSslSocket::sessionCipher() connect(socket, SIGNAL(sslErrors(QList)), this, SLOT(ignoreErrorSlot())); QVERIFY(socket->sessionCipher().isNull()); socket->connectToHost(QtNetworkSettings::serverName(), 443 /* https */); - QVERIFY(socket->waitForConnected(5000)); + QVERIFY(socket->waitForConnected(10000)); QVERIFY(socket->sessionCipher().isNull()); socket->startClientEncryption(); QVERIFY(socket->waitForEncrypted(5000)); @@ -684,7 +687,7 @@ void tst_QSslSocket::localCertificate() socket->setPrivateKey(QLatin1String(SRCDIR "certs/fluke.key")); socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); - QVERIFY(socket->waitForEncrypted(5000)); + QVERIFY(socket->waitForEncrypted(10000)); } void tst_QSslSocket::mode() @@ -1608,7 +1611,7 @@ void tst_QSslSocket::disconnectFromHostWhenConnecting() QCOMPARE(state, socket->state()); QVERIFY(socket->state() == QAbstractSocket::HostLookupState || socket->state() == QAbstractSocket::ConnectingState); - QVERIFY(socket->waitForDisconnected(5000)); + QVERIFY(socket->waitForDisconnected(10000)); QCOMPARE(socket->state(), QAbstractSocket::UnconnectedState); // we did not call close, so the socket must be still open QVERIFY(socket->isOpen()); -- cgit v0.12 From a722a716641d596b9a799e776e81167a47a261fa Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 25 Feb 2011 16:52:04 +0000 Subject: Fix for read on "connected" UDP sockets Symbian API RecvOneOrMore only supports stream oriented sockets. So for UDP we use RecvFrom instead and discard the source address. Reviewed-by: Markus Goetz --- src/network/socket/qsymbiansocketengine.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index b9537c1..e3b4a09 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -1049,10 +1049,16 @@ qint64 QSymbianSocketEngine::read(char *data, qint64 maxSize) TPtr8 buffer((TUint8*)data, (int)maxSize); TSockXfrLength received = 0; TRequestStatus status; - d->nativeSocket.RecvOneOrMore(buffer, 0, status, received); + TSockAddr dummy; + if (d->socketType == QAbstractSocket::UdpSocket) { + //RecvOneOrMore() can only be used with stream-interfaced connected sockets; datagram interface sockets will return KErrNotSupported. + d->nativeSocket.RecvFrom(buffer, dummy, 0, status); + } else { + d->nativeSocket.RecvOneOrMore(buffer, 0, status, received); + } User::WaitForRequest(status); //Non blocking receive TInt err = status.Int(); - int r = received(); + int r = buffer.Length(); if (err == KErrWouldBlock) { // No data was available for reading @@ -1064,9 +1070,9 @@ qint64 QSymbianSocketEngine::read(char *data, qint64 maxSize) } #if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QSymbianSocketEngine::read(%p \"%s\", %llu) == %i", + qDebug("QSymbianSocketEngine::read(%p \"%s\", %llu) == %i (err = %d)", data, qt_prettyDebug(data, qMin(r, ssize_t(16)), r).data(), - maxSize, r); + maxSize, r, err); #endif return qint64(r); -- cgit v0.12 From 37b6d6ef16606c11ba46ef4cb7c96e0989e78d7e Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 25 Feb 2011 17:24:50 +0000 Subject: Make socks5 socket engine push session down to real sockets This ensures the specified QNetworkSession from the QNetworkAccessManager is used to route the packets, when using a SOCKS proxy. Reviewed-by: Markus Goetz --- src/network/socket/qsocks5socketengine.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/network/socket/qsocks5socketengine.cpp b/src/network/socket/qsocks5socketengine.cpp index ab3d260..91dfdf3 100644 --- a/src/network/socket/qsocks5socketengine.cpp +++ b/src/network/socket/qsocks5socketengine.cpp @@ -556,6 +556,7 @@ void QSocks5SocketEnginePrivate::initialize(Socks5Mode socks5Mode) udpData = new QSocks5UdpAssociateData; data = udpData; udpData->udpSocket = new QUdpSocket(q); + udpData->udpSocket->setProperty("_q_networksession", q->property("_q_networksession")); udpData->udpSocket->setProxy(QNetworkProxy::NoProxy); QObject::connect(udpData->udpSocket, SIGNAL(readyRead()), q, SLOT(_q_udpSocketReadNotification()), @@ -567,6 +568,7 @@ void QSocks5SocketEnginePrivate::initialize(Socks5Mode socks5Mode) } data->controlSocket = new QTcpSocket(q); + data->controlSocket->setProperty("_q_networksession", q->property("_q_networksession")); data->controlSocket->setProxy(QNetworkProxy::NoProxy); QObject::connect(data->controlSocket, SIGNAL(connected()), q, SLOT(_q_controlSocketConnected()), Qt::DirectConnection); @@ -1376,6 +1378,7 @@ bool QSocks5SocketEngine::bind(const QHostAddress &address, quint16 port) d->udpData->associatePort = d->localPort; d->localPort = 0; QUdpSocket dummy; + dummy.setProperty("_q_networksession", property("_q_networksession")); dummy.setProxy(QNetworkProxy::NoProxy); if (!dummy.bind() || writeDatagram(0,0, d->data->controlSocket->localAddress(), dummy.localPort()) != 0 -- cgit v0.12 From 6c57e9a681bf82b9bcb4b0659d151a76ecd1455e Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 25 Feb 2011 17:59:40 +0000 Subject: Change an error code for behavioural compatibility qtcpsocket autotest checks for a specific error Reviewed-by: Markus Goetz --- src/network/socket/qsymbiansocketengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index e3b4a09..5dec4ee 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -368,7 +368,7 @@ bool QSymbianSocketEngine::initialize(int socketDescriptor, QAbstractSocket::Soc if (!QSymbianSocketManager::instance().lookupSocket(socketDescriptor, d->nativeSocket)) { qWarning("QSymbianSocketEngine::initialize - socket descriptor not found"); - d->setError(QAbstractSocket::SocketResourceError, + d->setError(QAbstractSocket::UnsupportedSocketOperationError, QSymbianSocketEnginePrivate::InvalidSocketErrorString); return false; } -- cgit v0.12 From 8d74ddeba364785bf3d0d0659e5bb91ab950540d Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 25 Feb 2011 18:01:58 +0000 Subject: Do not error socket when writeDatagram would block When starting a connection implicitly, datagrams fail with KErrWouldBlock on S60 5.0 and earlier. On symbian 3, they are dropped without error, but the bytes written is set to 0. Due to an apparent bug in symbian, the first packet is failed/dropped on a UDP socket even if the bearer is up due to existing TCP connection. With blocking sockets or explicit RConnection usage, this doesn't happen. Reviewed-by: Markus Goetz --- src/network/socket/qsymbiansocketengine.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index 5dec4ee..18ce5e0 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -845,8 +845,19 @@ qint64 QSymbianSocketEngine::writeDatagram(const char *data, qint64 len, User::WaitForRequest(status); //Non blocking send TInt err = status.Int(); +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug("QSymbianSocketEngine::writeDatagram(%p \"%s\", %lli, \"%s\", %i) == %lli (err=%d)", data, + qt_prettyDebug(data, qMin(len, 16), len).data(), len, host.toString().toLatin1().constData(), + port, (qint64) sentBytes(), err); +#endif + if (err) { switch (err) { + case KErrWouldBlock: + // do not error the socket. (otherwise socket layer is reset) + // On symbian^1 and earlier, KErrWouldBlock is returned when interface is not up yet + // On symbian^3, KErrNone is returned but sentBytes = 0 + return 0; case KErrTooBig: d->setError(QAbstractSocket::DatagramTooLargeError, d->DatagramTooLargeErrorString); break; @@ -855,13 +866,7 @@ qint64 QSymbianSocketEngine::writeDatagram(const char *data, qint64 len, } } -#if defined (QNATIVESOCKETENGINE_DEBUG) - qDebug("QSymbianSocketEnginePrivate::sendDatagram(%p \"%s\", %lli, \"%s\", %i) == %lli", data, - qt_prettyDebug(data, qMin(len, 16), len).data(), len, host.toString().toLatin1().constData(), - port, (qint64) sentBytes()); -#endif - - return qint64(sentBytes()); + return (err < 0) ? -1 : len; } // FIXME check where the native socket engine called that.. -- cgit v0.12 From 45531aceba4d0b2114942c49f4c256b70af58cf8 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 25 Feb 2011 18:22:06 +0000 Subject: Move UDP send length workaround from generic code to symbian engine Symbian workarounds are better in the symbian socket engine than generic layer, where this is possible. Reviewed-by: Markus Goetz --- src/network/socket/qsymbiansocketengine.cpp | 9 ++++++++- src/network/socket/qudpsocket.cpp | 10 ---------- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index 18ce5e0..dac50d4 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -864,9 +864,16 @@ qint64 QSymbianSocketEngine::writeDatagram(const char *data, qint64 len, default: d->setError(QAbstractSocket::NetworkError, d->SendDatagramErrorString); } + return -1; } - return (err < 0) ? -1 : len; + if (QSysInfo::s60Version() <= QSysInfo::SV_S60_5_0) { + // This is evil hack, but for some reason native RSocket::SendTo returns 0, + // for large datagrams (such as 600 bytes). Based on comments from Open C team + // this should happen only in platforms <= S60 5.0. + return len; + } + return sentBytes(); } // FIXME check where the native socket engine called that.. diff --git a/src/network/socket/qudpsocket.cpp b/src/network/socket/qudpsocket.cpp index 6a62b12..4334f68 100644 --- a/src/network/socket/qudpsocket.cpp +++ b/src/network/socket/qudpsocket.cpp @@ -504,16 +504,6 @@ qint64 QUdpSocket::writeDatagram(const char *data, qint64 size, const QHostAddre return -1; qint64 sent = d->socketEngine->writeDatagram(data, size, address, port); -#ifdef Q_OS_SYMBIAN - if( QSysInfo::s60Version() <= QSysInfo::SV_S60_5_0 ) { - // This is evil hack, but for some reason native RSocket::SendTo returns 0, - // for large datagrams (such as 600 bytes). Based on comments from Open C team - // this should happen only in platforms <= S60 5.0. - // As an workaround, we just set sent = size - if( sent == 0 ) - sent = size; - } -#endif d->cachedSocketDescriptor = d->socketEngine->socketDescriptor(); if (sent >= 0) { -- cgit v0.12 From 849ad907d49e6f6866dc81c0e3a94514bdc69b40 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 8 Mar 2011 18:46:00 +0000 Subject: Fix compile error introduced by merge Basically the same as f86e014bb6f2754bfed33106021a809ca8c2ce73. The declarations were appearing twice in the header file after merging Reviewed-by: Trust Me --- src/network/bearer/qnetworksession.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/network/bearer/qnetworksession.h b/src/network/bearer/qnetworksession.h index c08a9bf..688f37e 100644 --- a/src/network/bearer/qnetworksession.h +++ b/src/network/bearer/qnetworksession.h @@ -140,9 +140,6 @@ private: QNetworkSessionPrivate *d; }; -Q_DECLARE_METATYPE(QNetworkSession::State); -Q_DECLARE_METATYPE(QNetworkSession::SessionError); - #ifndef QT_MOBILITY_BEARER QT_END_NAMESPACE Q_DECLARE_METATYPE(QNetworkSession::State) -- cgit v0.12 From 5a488f8022626e71681ae42662aa9d4785ce6027 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 28 Feb 2011 19:32:55 +0000 Subject: Fix http proxy connections hanging on network error The http socket engine was hiding errors other than RemoteHostClosedError. This caused problems, because for other errors, the low level socket is still closed in the native socket engine. By not emitting the read notification, the error was never informed to QAbstractSocket and as a result, the application never gets the disconnected signal. Reviewed-by: Martin Petersson --- src/network/socket/qhttpsocketengine.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/network/socket/qhttpsocketengine.cpp b/src/network/socket/qhttpsocketengine.cpp index 6a025f2..598efb6 100644 --- a/src/network/socket/qhttpsocketengine.cpp +++ b/src/network/socket/qhttpsocketengine.cpp @@ -704,11 +704,10 @@ void QHttpSocketEngine::slotSocketError(QAbstractSocket::SocketError error) d->state = None; setError(error, d->socket->errorString()); - if (error == QAbstractSocket::RemoteHostClosedError) { - emitReadNotification(); - } else { + if (error != QAbstractSocket::RemoteHostClosedError) qDebug() << "QHttpSocketEngine::slotSocketError: got weird error =" << error; - } + //read notification needs to always be emitted, otherwise the higher layer doesn't get the disconnected signal + emitReadNotification(); } void QHttpSocketEngine::slotSocketStateChanged(QAbstractSocket::SocketState state) -- cgit v0.12 From 9530b97c6024ac69011ceb70dde06f5c71bd31d9 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 1 Mar 2011 16:22:33 +0000 Subject: QTcpSocket autotest fixes 1. Don't crash if qt-test-server isn't found, fail instead 2. symbian: 200ms is too short for the timeout test when using proxies, extended to 1000ms 3. Don't crash when the disconnectWhileConnectingNoEventLoop fails used a QScopedPointer with custom cleanup to shutdown the thread tidily. 4. Fast fail for downloadBigFile test if the connection is lost before the download is complete. This uses the disconnected signal to exit the event loop early. Previously on this type of failure it took 10 minutes for the event loop to time out. Reviewed-by: Markus Goetz --- tests/auto/qtcpsocket/tst_qtcpsocket.cpp | 33 ++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/tests/auto/qtcpsocket/tst_qtcpsocket.cpp b/tests/auto/qtcpsocket/tst_qtcpsocket.cpp index 21092c4..b0ecbda 100644 --- a/tests/auto/qtcpsocket/tst_qtcpsocket.cpp +++ b/tests/auto/qtcpsocket/tst_qtcpsocket.cpp @@ -336,7 +336,9 @@ void tst_QTcpSocket::init() QFETCH_GLOBAL(bool, setProxy); if (setProxy) { QFETCH_GLOBAL(int, proxyType); - QString fluke = QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().first().toString(); + QList addresses = QHostInfo::fromName(QtNetworkSettings::serverName()).addresses(); + QVERIFY2(addresses.count() > 0, "failed to get ip address for test server"); + QString fluke = addresses.first().toString(); QNetworkProxy proxy; switch (proxyType) { @@ -606,7 +608,7 @@ void tst_QTcpSocket::timeoutConnect() // Port 1357 is configured to drop packets on the test server socket->connectToHost(address, 1357); QVERIFY(timer.elapsed() < 50); - QVERIFY(!socket->waitForConnected(200)); + QVERIFY(!socket->waitForConnected(1000)); //200ms is too short when using SOCKS proxy authentication QCOMPARE(socket->state(), QTcpSocket::UnconnectedState); QCOMPARE(int(socket->error()), int(QTcpSocket::SocketTimeoutError)); @@ -1035,7 +1037,7 @@ public: : server(0), ok(false), quit(false) { } - ~ReceiverThread() { /*delete server;*/ terminate(); wait(); } + ~ReceiverThread() { } bool listen() { @@ -1047,6 +1049,14 @@ public: return true; } + static void cleanup(void *ptr) + { + ReceiverThread* self = reinterpret_cast(ptr); + self->quit = true; + self->wait(30000); + delete self; + } + protected: void run() { @@ -1093,18 +1103,16 @@ void tst_QTcpSocket::disconnectWhileConnectingNoEventLoop() { QFETCH(QByteArray, data); - ReceiverThread thread; - QVERIFY(thread.listen()); - thread.start(); + QScopedPointer thread (new ReceiverThread); + QVERIFY(thread->listen()); + thread->start(); // proceed to the connect-write-disconnect QTcpSocket *socket = newSocket(); - socket->connectToHost("127.0.0.1", thread.serverPort); + socket->connectToHost("127.0.0.1", thread->serverPort); if (!data.isEmpty()) socket->write(data); if (socket->state() == QAbstractSocket::ConnectedState) { - thread.quit = true; - thread.wait(); QSKIP("localhost connections are immediate, test case is invalid", SkipSingle); } @@ -1130,9 +1138,9 @@ void tst_QTcpSocket::disconnectWhileConnectingNoEventLoop() delete socket; // check if the other side received everything ok - QVERIFY(thread.wait(30000)); - QVERIFY(thread.ok); - QCOMPARE(thread.receivedData, data); + QVERIFY(thread->wait(30000)); + QVERIFY(thread->ok); + QCOMPARE(thread->receivedData, data); } //---------------------------------------------------------------------------------- @@ -1194,6 +1202,7 @@ void tst_QTcpSocket::downloadBigFile() connect(tmpSocket, SIGNAL(connected()), SLOT(exitLoopSlot())); connect(tmpSocket, SIGNAL(readyRead()), SLOT(downloadBigFileSlot())); + connect(tmpSocket, SIGNAL(disconnected()), SLOT(exitLoopSlot())); tmpSocket->connectToHost(QtNetworkSettings::serverName(), 80); -- cgit v0.12 From 270b878729068f42f862c7d04bb8a13915801ba3 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Wed, 2 Mar 2011 17:56:00 +0000 Subject: Thread safety - close RTimer handle when moving threads RTimer is only usable in the thread it was created. Reviewed-by: Markus Goetz --- src/network/socket/qsymbiansocketengine.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index dac50d4..fa6aedd 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -1665,16 +1665,26 @@ qint64 QSymbianSocketEngine::bytesToWrite() const bool QSymbianSocketEngine::event(QEvent* ev) { Q_D(QSymbianSocketEngine); +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug() << "QSymbianSocketEngine::event"; +#endif switch (ev->type()) { case QEvent::ThreadChange: +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug() << "ThreadChange"; +#endif if (d->asyncSelect) { delete d->asyncSelect; d->asyncSelect = 0; QEvent *postThreadChangeEvent = new QEvent(PostThreadChangeEvent); QCoreApplication::postEvent(this, postThreadChangeEvent); } + d->selectTimer.Close(); return true; case PostThreadChangeEvent: +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug() << "PostThreadChangeEvent"; +#endif // recreate select in new thread d->asyncSelect = q_check_ptr(new QAsyncSelect(0, d->nativeSocket, this)); if (d->readNotifier) { -- cgit v0.12 From dc9ddf8e30800aab375587563b377068bbe99532 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Wed, 2 Mar 2011 17:59:49 +0000 Subject: Fix crash Reviewed-by: Markus Goetz --- src/network/socket/qtcpserver.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/network/socket/qtcpserver.cpp b/src/network/socket/qtcpserver.cpp index 6b012db..5a60764 100644 --- a/src/network/socket/qtcpserver.cpp +++ b/src/network/socket/qtcpserver.cpp @@ -287,15 +287,15 @@ bool QTcpServer::listen(const QHostAddress &address, quint16 port) delete d->socketEngine; d->socketEngine = QAbstractSocketEngine::createSocketEngine(QAbstractSocket::TcpSocket, proxy, this); -#ifndef QT_NO_BEARERMANAGEMENT - //copy network session down to the socket engine (if it has been set) - d->socketEngine->setProperty("_q_networksession", property("_q_networksession")); -#endif if (!d->socketEngine) { d->serverSocketError = QAbstractSocket::UnsupportedSocketOperationError; d->serverSocketErrorString = tr("Operation on socket is not supported"); return false; } +#ifndef QT_NO_BEARERMANAGEMENT + //copy network session down to the socket engine (if it has been set) + d->socketEngine->setProperty("_q_networksession", property("_q_networksession")); +#endif if (!d->socketEngine->initialize(QAbstractSocket::TcpSocket, proto)) { d->serverSocketError = d->socketEngine->error(); d->serverSocketErrorString = d->socketEngine->errorString(); -- cgit v0.12 From 76342796aa83761a854fd8c0b477af0a1afc62c4 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 4 Mar 2011 18:56:55 +0000 Subject: Move some network tests from gui.pro to network.pro These network tests have no dependency on the QtGui dll, so I have moved them to the network autotest group. In some cases this was not stated in the tests' .pro files. The gui autotest group still has a network test (qtcpsocket), but this has a dependency on QtGui for one test case (which uses QMessageBox) Reviewed-by: Markus Goetz --- tests/auto/gui.pro | 5 ----- tests/auto/network.pro | 5 +++++ tests/auto/qnetworkcachemetadata/qnetworkcachemetadata.pro | 1 + tests/auto/qnetworkdiskcache/qnetworkdiskcache.pro | 1 + tests/auto/qnetworkreply/test/test.pro | 1 + 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/tests/auto/gui.pro b/tests/auto/gui.pro index 07dc5ef..356a98d 100644 --- a/tests/auto/gui.pro +++ b/tests/auto/gui.pro @@ -113,9 +113,6 @@ SUBDIRS=\ qmouseevent_modal \ qmovie \ qnetworkaccessmanager_and_qprogressdialog \ - qnetworkcachemetadata \ - qnetworkdiskcache \ - qnetworkreply \ qpaintengine \ qpainterpath \ qpainterpathstroker \ @@ -168,7 +165,6 @@ SUBDIRS=\ qtabbar \ qtableview \ qtablewidget \ - qtcpserver \ qtcpsocket \ qtessellator \ qtextblock \ @@ -195,7 +191,6 @@ SUBDIRS=\ qtreeview \ qtreewidget \ qtreewidgetitemiterator \ - qudpsocket \ qundogroup \ qundostack \ qvectornd \ diff --git a/tests/auto/network.pro b/tests/auto/network.pro index 50c4487..e4cecce 100644 --- a/tests/auto/network.pro +++ b/tests/auto/network.pro @@ -19,12 +19,15 @@ SUBDIRS=\ platformsocketengine \ qnetworkaccessmanager \ qnetworkaddressentry \ + qnetworkcachemetadata \ qnetworkconfiguration \ qnetworkconfigurationmanager \ qnetworkcookie \ qnetworkcookiejar \ + qnetworkdiskcache \ qnetworkinterface \ qnetworkproxy \ + qnetworkreply \ qnetworkrequest \ qnetworksession \ qobjectperformance \ @@ -37,6 +40,8 @@ SUBDIRS=\ qsslsocket \ qsslsocket_onDemandCertificates_member \ qsslsocket_onDemandCertificates_static \ + qtcpserver \ + qudpsocket \ # qnetworkproxyfactory \ # Uses a hardcoded proxy configuration !contains(QT_CONFIG, private_tests): SUBDIRS -= \ diff --git a/tests/auto/qnetworkcachemetadata/qnetworkcachemetadata.pro b/tests/auto/qnetworkcachemetadata/qnetworkcachemetadata.pro index 77ad347..ae0941e 100644 --- a/tests/auto/qnetworkcachemetadata/qnetworkcachemetadata.pro +++ b/tests/auto/qnetworkcachemetadata/qnetworkcachemetadata.pro @@ -1,4 +1,5 @@ load(qttest_p4) +QT -= gui QT += network SOURCES += tst_qnetworkcachemetadata.cpp diff --git a/tests/auto/qnetworkdiskcache/qnetworkdiskcache.pro b/tests/auto/qnetworkdiskcache/qnetworkdiskcache.pro index 3b13087..c05171d 100644 --- a/tests/auto/qnetworkdiskcache/qnetworkdiskcache.pro +++ b/tests/auto/qnetworkdiskcache/qnetworkdiskcache.pro @@ -1,4 +1,5 @@ load(qttest_p4) +QT -= gui QT += network SOURCES += tst_qnetworkdiskcache.cpp diff --git a/tests/auto/qnetworkreply/test/test.pro b/tests/auto/qnetworkreply/test/test.pro index 12fdf04..80b879a 100644 --- a/tests/auto/qnetworkreply/test/test.pro +++ b/tests/auto/qnetworkreply/test/test.pro @@ -1,4 +1,5 @@ load(qttest_p4) +QT -= gui SOURCES += ../tst_qnetworkreply.cpp TARGET = ../tst_qnetworkreply -- cgit v0.12 From 3d34e2e49399446b45a343dcff917afef748520b Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 4 Mar 2011 19:06:05 +0000 Subject: Fix link error in qsocketnotifier test Reviewed-by: Markus Goetz --- tests/auto/qsocketnotifier/tst_qsocketnotifier.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/auto/qsocketnotifier/tst_qsocketnotifier.cpp b/tests/auto/qsocketnotifier/tst_qsocketnotifier.cpp index 0b7e7ef..5594dc3 100644 --- a/tests/auto/qsocketnotifier/tst_qsocketnotifier.cpp +++ b/tests/auto/qsocketnotifier/tst_qsocketnotifier.cpp @@ -46,7 +46,13 @@ #include #include #include +#ifdef Q_OS_SYMBIAN +#include +#define NATIVESOCKETENGINE QSymbianSocketEngine +#else #include +#define NATIVESOCKETENGINE QNativeSocketEngine +#endif class tst_QSocketNotifier : public QObject { @@ -71,10 +77,10 @@ class UnexpectedDisconnectTester : public QObject { Q_OBJECT public: - QNativeSocketEngine *readEnd1, *readEnd2; + NATIVESOCKETENGINE *readEnd1, *readEnd2; int sequence; - UnexpectedDisconnectTester(QNativeSocketEngine *s1, QNativeSocketEngine *s2) + UnexpectedDisconnectTester(NATIVESOCKETENGINE *s1, NATIVESOCKETENGINE *s2) : readEnd1(s1), readEnd2(s2), sequence(0) { QSocketNotifier *notifier1 = @@ -124,7 +130,7 @@ void tst_QSocketNotifier::unexpectedDisconnection() QTcpServer server; QVERIFY(server.listen(QHostAddress::LocalHost, 0)); - QNativeSocketEngine readEnd1; + NATIVESOCKETENGINE readEnd1; readEnd1.initialize(QAbstractSocket::TcpSocket); bool b = readEnd1.connectToHost(server.serverAddress(), server.serverPort()); QVERIFY(readEnd1.waitForWrite()); @@ -135,7 +141,7 @@ void tst_QSocketNotifier::unexpectedDisconnection() QTcpSocket *writeEnd1 = server.nextPendingConnection(); QVERIFY(writeEnd1 != 0); - QNativeSocketEngine readEnd2; + NATIVESOCKETENGINE readEnd2; readEnd2.initialize(QAbstractSocket::TcpSocket); b = readEnd2.connectToHost(server.serverAddress(), server.serverPort()); QVERIFY(readEnd2.waitForWrite()); -- cgit v0.12 From 81ab8365e53389936bcaff07c82a2891ec63c4e5 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 7 Mar 2011 17:14:02 +0000 Subject: Reduce excessive timeout in tst_qtcpsocket Timeout of 5000 seconds (which was probably intended to be 5000ms) reduced to a more reasonable 60 seconds, to prevent the test from hanging in case of errors in the proxy server. Reviewed-by: Markus Goetz --- tests/auto/qtcpsocket/tst_qtcpsocket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/qtcpsocket/tst_qtcpsocket.cpp b/tests/auto/qtcpsocket/tst_qtcpsocket.cpp index b0ecbda..40ca531 100644 --- a/tests/auto/qtcpsocket/tst_qtcpsocket.cpp +++ b/tests/auto/qtcpsocket/tst_qtcpsocket.cpp @@ -1389,7 +1389,7 @@ void tst_QTcpSocket::flush() connect(socket, SIGNAL(connected()), SLOT(exitLoopSlot())); socket->connectToHost(QtNetworkSettings::serverName(), 143); - enterLoop(5000); + enterLoop(60); QVERIFY(socket->isOpen()); socket->write("1 LOGOUT\r\n"); -- cgit v0.12 From a99cc33345c32a7e210dbffa2c5c56ee13dd83c1 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 8 Mar 2011 13:20:40 +0000 Subject: tst_qtcpsocket stabilisation Increased heap size to avoid OOM Increased timeouts in the timeoutConnect test, as these randomly fail at least in debug builds with 50ms (symbian threads have a 20ms timeslice for round robin scheduling of equal priority threads, so that could be related) Skip the setSocketDescriptor test on symbian, since native sockets are not ints, open c sockets are not supported, and we decided not to support RSocket adoption unless it's specifically requested. Reviewed-by: Markus Goetz --- tests/auto/qtcpsocket/test/test.pro | 2 +- tests/auto/qtcpsocket/tst_qtcpsocket.cpp | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/auto/qtcpsocket/test/test.pro b/tests/auto/qtcpsocket/test/test.pro index c4369df..5dde565 100644 --- a/tests/auto/qtcpsocket/test/test.pro +++ b/tests/auto/qtcpsocket/test/test.pro @@ -11,7 +11,7 @@ wince*: { QT += network vxworks:QT -= gui -symbian: TARGET.EPOCHEAPSIZE="0x100 0x1000000" +symbian: TARGET.EPOCHEAPSIZE="0x100 0x3000000" TARGET = tst_qtcpsocket diff --git a/tests/auto/qtcpsocket/tst_qtcpsocket.cpp b/tests/auto/qtcpsocket/tst_qtcpsocket.cpp index 40ca531..b21de49 100644 --- a/tests/auto/qtcpsocket/tst_qtcpsocket.cpp +++ b/tests/auto/qtcpsocket/tst_qtcpsocket.cpp @@ -445,6 +445,9 @@ void tst_QTcpSocket::setInvalidSocketDescriptor() void tst_QTcpSocket::setSocketDescriptor() { +#ifdef Q_OS_SYMBIAN + QSKIP("adopting open c socket handles is not supported", SkipAll); +#else QFETCH_GLOBAL(bool, setProxy); if (setProxy) return; // this test doesn't make sense with proxies @@ -485,6 +488,7 @@ void tst_QTcpSocket::setSocketDescriptor() #ifdef Q_OS_WIN delete dummy; #endif +#endif } //---------------------------------------------------------------------------------- @@ -607,14 +611,14 @@ void tst_QTcpSocket::timeoutConnect() // Port 1357 is configured to drop packets on the test server socket->connectToHost(address, 1357); - QVERIFY(timer.elapsed() < 50); + QVERIFY(timer.elapsed() < 150); QVERIFY(!socket->waitForConnected(1000)); //200ms is too short when using SOCKS proxy authentication QCOMPARE(socket->state(), QTcpSocket::UnconnectedState); QCOMPARE(int(socket->error()), int(QTcpSocket::SocketTimeoutError)); timer.start(); socket->connectToHost(address, 1357); - QVERIFY(timer.elapsed() < 50); + QVERIFY(timer.elapsed() < 150); QTimer::singleShot(50, &QTestEventLoop::instance(), SLOT(exitLoop())); QTestEventLoop::instance().enterLoop(5); QVERIFY(!QTestEventLoop::instance().timeout()); -- cgit v0.12 From f89c25376651a87501e0c5980d289992b0fbe1c8 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 8 Mar 2011 15:41:59 +0000 Subject: Handle errors returned through select in the waitForXXX socket functions Reviewed-by: Markus Goetz --- src/network/socket/qsymbiansocketengine.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index fa6aedd..ed7962c 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -1141,6 +1141,9 @@ int QSymbianSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool //restart asynchronous notifier (only one IOCTL allowed at a time) if (asyncSelect) asyncSelect->IssueRequest(); +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug() << "QSymbianSocketEnginePrivate::nativeSelect: select timeout"; +#endif return 0; //timeout } else { selectTimer.Cancel(); @@ -1148,11 +1151,20 @@ int QSymbianSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool } } +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug() << "QSymbianSocketEnginePrivate::nativeSelect: select status" << selectStat.Int() << (int)selectFlags(); +#endif if (selectStat != KErrNone) return selectStat.Int(); if (selectFlags() & KSockSelectExcept) { TInt err; nativeSocket.GetOpt(KSOSelectLastError, KSOLSocket, err); +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug() << "QSymbianSocketEnginePrivate::nativeSelect: select last error" << err; +#endif + //TODO: avoidable cast? + //set the error here, because read won't always return the same error again as select. + const_cast(this)->setError(err); //restart asynchronous notifier (only one IOCTL allowed at a time) if (asyncSelect) asyncSelect->IssueRequest(); //TODO: in error case should we restart or not? @@ -1381,6 +1393,7 @@ void QSymbianSocketEnginePrivate::setError(TInt symbianError) switch (symbianError) { case KErrDisconnected: case KErrEof: + case KErrConnectionTerminated: //interface stopped externally - RConnection::Stop(EStopAuthoritative) setError(QAbstractSocket::RemoteHostClosedError, QSymbianSocketEnginePrivate::RemoteHostClosedErrorString); break; -- cgit v0.12 From 0b0247e675e3e8054e41de41c716d8f915e18629 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 8 Mar 2011 14:17:47 +0000 Subject: tst_qtcpsocket - skip proxies for localhost testing There is no point to test the proxy setting for connections to localhost, because the proxy is bypassed anyway. Skipping running the same test case multiple times makes this test complete a bit faster. Reviewed-by: Markus Goetz --- tests/auto/qtcpsocket/tst_qtcpsocket.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/auto/qtcpsocket/tst_qtcpsocket.cpp b/tests/auto/qtcpsocket/tst_qtcpsocket.cpp index b21de49..b972130 100644 --- a/tests/auto/qtcpsocket/tst_qtcpsocket.cpp +++ b/tests/auto/qtcpsocket/tst_qtcpsocket.cpp @@ -981,6 +981,9 @@ void tst_QTcpSocket::disconnectWhileConnecting_data() void tst_QTcpSocket::disconnectWhileConnecting() { QFETCH(QByteArray, data); + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; //proxy not useful for localhost test case QTcpServer server; QVERIFY(server.listen(QHostAddress::LocalHost)); @@ -1106,6 +1109,9 @@ void tst_QTcpSocket::disconnectWhileConnectingNoEventLoop_data() void tst_QTcpSocket::disconnectWhileConnectingNoEventLoop() { QFETCH(QByteArray, data); + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; //proxy not useful for localhost test case QScopedPointer thread (new ReceiverThread); QVERIFY(thread->listen()); @@ -1646,6 +1652,9 @@ private slots: //---------------------------------------------------------------------------------- void tst_QTcpSocket::remoteCloseError() { + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; //proxy not useful for localhost test case RemoteCloseErrorServer server; QVERIFY(server.listen(QHostAddress::LocalHost)); @@ -1956,6 +1965,9 @@ void tst_QTcpSocket::linuxKernelBugLocalSocket() //---------------------------------------------------------------------------------- void tst_QTcpSocket::abortiveClose() { + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; //proxy not useful for localhost test case QTcpServer server; QVERIFY(server.listen(QHostAddress::LocalHost)); connect(&server, SIGNAL(newConnection()), this, SLOT(exitLoopSlot())); @@ -1994,6 +2006,9 @@ void tst_QTcpSocket::abortiveClose_abortSlot() //---------------------------------------------------------------------------------- void tst_QTcpSocket::localAddressEmptyOnBSD() { + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; //proxy not useful for localhost test case QTcpServer server; QVERIFY(server.listen(QHostAddress::LocalHost)); @@ -2264,6 +2279,9 @@ void tst_QTcpSocket::moveToThread0() void tst_QTcpSocket::increaseReadBufferSize() { + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; //proxy not useful for localhost test case QTcpServer server; QTcpSocket *active = newSocket(); connect(active, SIGNAL(readyRead()), SLOT(exitLoopSlot())); -- cgit v0.12 From 28100e436bb662756c2cb0be471785bcd2dbef83 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 8 Mar 2011 18:01:54 +0000 Subject: tst_qudpsocket - add a non localhost test case The echo test case uses the UDP echo service on the qt-test-server Reviewed-by: Markus Goetz --- tests/auto/qudpsocket/tst_qudpsocket.cpp | 52 ++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/tests/auto/qudpsocket/tst_qudpsocket.cpp b/tests/auto/qudpsocket/tst_qudpsocket.cpp index 6ba55b2..e6fe068 100644 --- a/tests/auto/qudpsocket/tst_qudpsocket.cpp +++ b/tests/auto/qudpsocket/tst_qudpsocket.cpp @@ -108,6 +108,8 @@ private slots: void setMulticastInterface(); void multicast_data(); void multicast(); + void echo_data(); + void echo(); protected slots: void empty_readyReadSlot(); @@ -1095,5 +1097,55 @@ void tst_QUdpSocket::multicast() QVERIFY2(receiver.leaveMulticastGroup(groupAddress), qPrintable(receiver.errorString())); } +void tst_QUdpSocket::echo_data() +{ + QTest::addColumn("connect"); + QTest::newRow("writeDatagram") << false; + QTest::newRow("write") << true; +} + +void tst_QUdpSocket::echo() +{ + QFETCH(bool, connect); + QHostInfo info = QHostInfo::fromName(QtNetworkSettings::serverName()); + QVERIFY(info.addresses().count()); + QHostAddress remote = info.addresses().first(); + + QUdpSocket sock; + if (connect) { + sock.connectToHost(remote, 7); + } else { + sock.bind(); + } + QByteArray out(30, 'x'); + QByteArray in; + int successes = 0; + for (int i=0;i<20;i++) { + if (connect) { + sock.write(out); + } else { + sock.writeDatagram(out, remote, 7); + } + if (sock.waitForReadyRead(1000)) { + while (sock.hasPendingDatagrams()) { + QHostAddress from; + quint16 port; + if (connect) { + in = sock.read(sock.pendingDatagramSize()); + } else { + in.resize(sock.pendingDatagramSize()); + sock.readDatagram(in.data(), in.length(), &from, &port); + } + if (in==out) + successes++; + } + } + if (!sock.isValid()) + QFAIL(sock.errorString().toLatin1().constData()); + qDebug() << "packets in" << successes << "out" << i; + } + QVERIFY(successes >= 18); +} + QTEST_MAIN(tst_QUdpSocket) #include "tst_qudpsocket.moc" -- cgit v0.12 From 0b646f2336a17aa6ae1cb4da89cba71c1adfd5ed Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Wed, 9 Mar 2011 13:46:57 +0000 Subject: Network session support for proxy socket engines The proxy socket engines forward the network session to the "real" socket they use natively. Reviewed-by: Markus Goetz --- src/network/socket/qhttpsocketengine.cpp | 3 +++ src/network/socket/qsocks5socketengine.cpp | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/src/network/socket/qhttpsocketengine.cpp b/src/network/socket/qhttpsocketengine.cpp index 598efb6..c580b03 100644 --- a/src/network/socket/qhttpsocketengine.cpp +++ b/src/network/socket/qhttpsocketengine.cpp @@ -72,6 +72,9 @@ bool QHttpSocketEngine::initialize(QAbstractSocket::SocketType type, QAbstractSo setProtocol(protocol); setSocketType(type); d->socket = new QTcpSocket(this); +#ifndef QT_NO_BEARERMANAGEMENT + d->socket->setProperty("_q_networkSession", property("_q_networkSession")); +#endif // Explicitly disable proxying on the proxy socket itself to avoid // unwanted recursion. diff --git a/src/network/socket/qsocks5socketengine.cpp b/src/network/socket/qsocks5socketengine.cpp index 91dfdf3..16c0faa 100644 --- a/src/network/socket/qsocks5socketengine.cpp +++ b/src/network/socket/qsocks5socketengine.cpp @@ -556,7 +556,9 @@ void QSocks5SocketEnginePrivate::initialize(Socks5Mode socks5Mode) udpData = new QSocks5UdpAssociateData; data = udpData; udpData->udpSocket = new QUdpSocket(q); +#ifndef QT_NO_BEARERMANAGEMENT udpData->udpSocket->setProperty("_q_networksession", q->property("_q_networksession")); +#endif udpData->udpSocket->setProxy(QNetworkProxy::NoProxy); QObject::connect(udpData->udpSocket, SIGNAL(readyRead()), q, SLOT(_q_udpSocketReadNotification()), @@ -568,7 +570,9 @@ void QSocks5SocketEnginePrivate::initialize(Socks5Mode socks5Mode) } data->controlSocket = new QTcpSocket(q); +#ifndef QT_NO_BEARERMANAGEMENT data->controlSocket->setProperty("_q_networksession", q->property("_q_networksession")); +#endif data->controlSocket->setProxy(QNetworkProxy::NoProxy); QObject::connect(data->controlSocket, SIGNAL(connected()), q, SLOT(_q_controlSocketConnected()), Qt::DirectConnection); @@ -1378,7 +1382,9 @@ bool QSocks5SocketEngine::bind(const QHostAddress &address, quint16 port) d->udpData->associatePort = d->localPort; d->localPort = 0; QUdpSocket dummy; +#ifndef QT_NO_BEARERMANAGEMENT dummy.setProperty("_q_networksession", property("_q_networksession")); +#endif dummy.setProxy(QNetworkProxy::NoProxy); if (!dummy.bind() || writeDatagram(0,0, d->data->controlSocket->localAddress(), dummy.localPort()) != 0 -- cgit v0.12 From f2d8211aa530c6aca65bd52fd4cc57ef74f927c0 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Wed, 9 Mar 2011 17:22:35 +0000 Subject: Add debug logging to QHttpThreadDelegate Activated by defining QHTTPTHREADDELEGATE_DEBUG Reviewed-by: Markus Goetz --- src/network/access/qhttpthreaddelegate.cpp | 38 ++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp index b5cf00a..2cd5979 100644 --- a/src/network/access/qhttpthreaddelegate.cpp +++ b/src/network/access/qhttpthreaddelegate.cpp @@ -39,6 +39,7 @@ ** ****************************************************************************/ +//#define QHTTPTHREADDELEGATE_DEBUG #include "qhttpthreaddelegate_p.h" #include @@ -196,6 +197,9 @@ QHttpThreadDelegate::QHttpThreadDelegate(QObject *parent) : // This is invoked as BlockingQueuedConnection from QNetworkAccessHttpBackend in the user thread void QHttpThreadDelegate::startRequestSynchronously() { +#ifdef QHTTPTHREADDELEGATE_DEBUG + qDebug() << "QHttpThreadDelegate::startRequestSynchronously() thread=" << QThread::currentThreadId(); +#endif synchronous = true; QEventLoop synchronousRequestLoop; @@ -210,12 +214,18 @@ void QHttpThreadDelegate::startRequestSynchronously() connections.localData()->releaseEntry(cacheKey); connections.setLocalData(0); +#ifdef QHTTPTHREADDELEGATE_DEBUG + qDebug() << "QHttpThreadDelegate::startRequestSynchronously() thread=" << QThread::currentThreadId() << "finished"; +#endif } // This is invoked as QueuedConnection from QNetworkAccessHttpBackend in the user thread void QHttpThreadDelegate::startRequest() { +#ifdef QHTTPTHREADDELEGATE_DEBUG + qDebug() << "QHttpThreadDelegate::startRequest() thread=" << QThread::currentThreadId(); +#endif // Check QThreadStorage for the QNetworkAccessCache // If not there, create this connection cache if (!connections.hasLocalData()) { @@ -300,6 +310,9 @@ void QHttpThreadDelegate::startRequest() // This gets called from the user thread or by the synchronous HTTP timeout timer void QHttpThreadDelegate::abortRequest() { +#ifdef QHTTPTHREADDELEGATE_DEBUG + qDebug() << "QHttpThreadDelegate::abortRequest() thread=" << QThread::currentThreadId() << "sync=" << synchronous; +#endif if (httpReply) { delete httpReply; httpReply = 0; @@ -329,6 +342,9 @@ void QHttpThreadDelegate::finishedSlot() qWarning() << "QHttpThreadDelegate::finishedSlot: HTTP reply had already been deleted, internal problem. Please report."; return; } +#ifdef QHTTPTHREADDELEGATE_DEBUG + qDebug() << "QHttpThreadDelegate::finishedSlot() thread=" << QThread::currentThreadId() << "result=" << httpReply->statusCode(); +#endif // If there is still some data left emit that now while (httpReply->readAnyAvailable()) { @@ -358,6 +374,9 @@ void QHttpThreadDelegate::finishedSlot() void QHttpThreadDelegate::synchronousFinishedSlot() { +#ifdef QHTTPTHREADDELEGATE_DEBUG + qDebug() << "QHttpThreadDelegate::synchronousFinishedSlot() thread=" << QThread::currentThreadId() << "result=" << httpReply->statusCode(); +#endif if (httpReply->statusCode() >= 400) { // it's an error reply QString msg = QLatin1String(QT_TRANSLATE_NOOP("QNetworkReply", @@ -379,6 +398,9 @@ void QHttpThreadDelegate::finishedWithErrorSlot(QNetworkReply::NetworkError erro qWarning() << "QHttpThreadDelegate::finishedWithErrorSlot: HTTP reply had already been deleted, internal problem. Please report."; return; } +#ifdef QHTTPTHREADDELEGATE_DEBUG + qDebug() << "QHttpThreadDelegate::finishedWithErrorSlot() thread=" << QThread::currentThreadId() << "error=" << errorCode << detail; +#endif #ifndef QT_NO_OPENSSL if (ssl) @@ -396,6 +418,9 @@ void QHttpThreadDelegate::finishedWithErrorSlot(QNetworkReply::NetworkError erro void QHttpThreadDelegate::synchronousFinishedWithErrorSlot(QNetworkReply::NetworkError errorCode, const QString &detail) { +#ifdef QHTTPTHREADDELEGATE_DEBUG + qDebug() << "QHttpThreadDelegate::synchronousFinishedWithErrorSlot() thread=" << QThread::currentThreadId() << "error=" << errorCode << detail; +#endif incomingErrorCode = errorCode; incomingErrorDetail = detail; @@ -411,6 +436,10 @@ static void downloadBufferDeleter(char *ptr) void QHttpThreadDelegate::headerChangedSlot() { +#ifdef QHTTPTHREADDELEGATE_DEBUG + qDebug() << "QHttpThreadDelegate::headerChangedSlot() thread=" << QThread::currentThreadId(); +#endif + #ifndef QT_NO_OPENSSL if (ssl) emit sslConfigurationChanged(httpReply->sslConfiguration()); @@ -443,6 +472,9 @@ void QHttpThreadDelegate::headerChangedSlot() void QHttpThreadDelegate::synchronousHeaderChangedSlot() { +#ifdef QHTTPTHREADDELEGATE_DEBUG + qDebug() << "QHttpThreadDelegate::synchronousHeaderChangedSlot() thread=" << QThread::currentThreadId(); +#endif // Store the information we need in this object, the QNetworkAccessHttpBackend will later read it incomingHeaders = httpReply->header(); incomingStatusCode = httpReply->statusCode(); @@ -487,6 +519,9 @@ void QHttpThreadDelegate::sslErrorsSlot(const QList &errors) void QHttpThreadDelegate::synchronousAuthenticationRequiredSlot(const QHttpNetworkRequest &request, QAuthenticator *a) { Q_UNUSED(request); +#ifdef QHTTPTHREADDELEGATE_DEBUG + qDebug() << "QHttpThreadDelegate::synchronousAuthenticationRequiredSlot() thread=" << QThread::currentThreadId(); +#endif // Ask the credential cache QNetworkAuthenticationCredential credential = authenticationManager->fetchCachedCredentials(httpRequest.url(), a); @@ -502,6 +537,9 @@ void QHttpThreadDelegate::synchronousAuthenticationRequiredSlot(const QHttpNetwo #ifndef QT_NO_NETWORKPROXY void QHttpThreadDelegate::synchronousProxyAuthenticationRequiredSlot(const QNetworkProxy &p, QAuthenticator *a) { +#ifdef QHTTPTHREADDELEGATE_DEBUG + qDebug() << "QHttpThreadDelegate::synchronousProxyAuthenticationRequiredSlot() thread=" << QThread::currentThreadId(); +#endif // Ask the credential cache QNetworkAuthenticationCredential credential = authenticationManager->fetchCachedProxyCredentials(p, a); if (!credential.isNull()) { -- cgit v0.12 From 7b34e64198cbcdb8d738c9da11abe08c0ac880ac Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Wed, 9 Mar 2011 17:33:17 +0000 Subject: Fix synchronous http deadlock when aborted by internal timeout QHttpThreadDelegate::abortRequest was deleting itself, but not exiting the event loop. For the synchronous usage, both these are incorrect. Without exiting the event loop, the main thread waits forever. If it deletes itself, then the main thread will access the deleted memory on return (the delegate->incomingErrorCode class member) which can crash with frequency depending on heap implementation. With this change, abort acts more like the synchronousFinishedWithErrorSlot. Reviewed-by: Markus Goetz --- src/network/access/qhttpthreaddelegate.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp index 2cd5979..d75f12c 100644 --- a/src/network/access/qhttpthreaddelegate.cpp +++ b/src/network/access/qhttpthreaddelegate.cpp @@ -191,6 +191,7 @@ QHttpThreadDelegate::QHttpThreadDelegate(QObject *parent) : , downloadBuffer(0) , httpConnection(0) , httpReply(0) + , synchronousRequestLoop(0) { } @@ -316,12 +317,16 @@ void QHttpThreadDelegate::abortRequest() if (httpReply) { delete httpReply; httpReply = 0; - this->deleteLater(); } // Got aborted by the timeout timer - if (synchronous) + if (synchronous) { incomingErrorCode = QNetworkReply::TimeoutError; + QMetaObject::invokeMethod(synchronousRequestLoop, "quit", Qt::QueuedConnection); + } else { + //only delete this for asynchronous mode or QNetworkAccessHttpBackend will crash - see QNetworkAccessHttpBackend::postRequest() + this->deleteLater(); + } } void QHttpThreadDelegate::readyReadSlot() -- cgit v0.12 From ef53143777ccbd73799e597792a46b2676932cc2 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Wed, 9 Mar 2011 17:41:38 +0000 Subject: Bearer support for threaded http backend Reviewed-by: Markus Goetz --- src/network/access/qhttpthreaddelegate.cpp | 9 +++++++++ src/network/access/qhttpthreaddelegate_p.h | 3 +++ src/network/access/qnetworkaccesshttpbackend.cpp | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp index d75f12c..6d6fadd 100644 --- a/src/network/access/qhttpthreaddelegate.cpp +++ b/src/network/access/qhttpthreaddelegate.cpp @@ -142,8 +142,13 @@ class QNetworkAccessCachedHttpConnection: public QHttpNetworkConnection, { // Q_OBJECT public: +#ifdef QT_NO_BEARERMANAGEMENT QNetworkAccessCachedHttpConnection(const QString &hostName, quint16 port, bool encrypt) : QHttpNetworkConnection(hostName, port, encrypt) +#else + QNetworkAccessCachedHttpConnection(const QString &hostName, quint16 port, bool encrypt, QSharedPointer networkSession) + : QHttpNetworkConnection(hostName, port, encrypt, /*parent=*/0, networkSession) +#endif { setExpires(true); setShareable(true); @@ -250,7 +255,11 @@ void QHttpThreadDelegate::startRequest() if (httpConnection == 0) { // no entry in cache; create an object // the http object is actually a QHttpNetworkConnection +#ifdef QT_NO_BEARERMANAGEMENT httpConnection = new QNetworkAccessCachedHttpConnection(urlCopy.host(), urlCopy.port(), ssl); +#else + httpConnection = new QNetworkAccessCachedHttpConnection(urlCopy.host(), urlCopy.port(), ssl, networkSession); +#endif #ifndef QT_NO_OPENSSL // Set the QSslConfiguration from this QNetworkRequest. if (ssl) { diff --git a/src/network/access/qhttpthreaddelegate_p.h b/src/network/access/qhttpthreaddelegate_p.h index 086a35d..2e86df3 100644 --- a/src/network/access/qhttpthreaddelegate_p.h +++ b/src/network/access/qhttpthreaddelegate_p.h @@ -110,6 +110,9 @@ public: qint64 incomingContentLength; QNetworkReply::NetworkError incomingErrorCode; QString incomingErrorDetail; +#ifndef QT_NO_BEARERMANAGEMENT + QSharedPointer networkSession; +#endif protected: // The zerocopy download buffer, if used: diff --git a/src/network/access/qnetworkaccesshttpbackend.cpp b/src/network/access/qnetworkaccesshttpbackend.cpp index 4908e0a..8a29a31 100644 --- a/src/network/access/qnetworkaccesshttpbackend.cpp +++ b/src/network/access/qnetworkaccesshttpbackend.cpp @@ -47,6 +47,7 @@ #include "qabstractnetworkcache.h" #include "qnetworkrequest.h" #include "qnetworkreply.h" +#include "QtNetwork/private/qnetworksession_p.h" #include "qnetworkrequest_p.h" #include "qnetworkcookie_p.h" #include "QtCore/qdatetime.h" @@ -519,6 +520,11 @@ void QNetworkAccessHttpBackend::postRequest() // Create the HTTP thread delegate QHttpThreadDelegate *delegate = new QHttpThreadDelegate; +#ifndef Q_NO_BEARERMANAGEMENT + QVariant v(property("_q_networksession")); + if (v.isValid()) + delegate->networkSession = qvariant_cast >(v); +#endif // For the synchronous HTTP, this is the normal way the delegate gets deleted // For the asynchronous HTTP this is a safety measure, the delegate deletes itself when HTTP is finished -- cgit v0.12 From 132566afcf2357cc3c77d940f22567d83951f21d Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Thu, 10 Mar 2011 14:40:01 +0000 Subject: Fix network session use with the localhost optimisation in QNAB QNetworkAccessBackend has an optimisation to not start the bearer when the destination is localhost. On symbian, if the bearer is specified but not started, then socket creation will fail. To fix this, delay pushing the network session until start() is called, at which point we know if the localhost optmisation will be applied or not. When using localhost, don't specify any network session - symbian socket engine will create the socket successfully in thie case. Reviewed-by: Markus Goetz --- src/network/access/qnetworkaccessbackend.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/network/access/qnetworkaccessbackend.cpp b/src/network/access/qnetworkaccessbackend.cpp index 8f5a3da..6220abe 100644 --- a/src/network/access/qnetworkaccessbackend.cpp +++ b/src/network/access/qnetworkaccessbackend.cpp @@ -96,11 +96,6 @@ QNetworkAccessBackend *QNetworkAccessManagerPrivate::findBackend(QNetworkAccessM QNetworkAccessBackend *backend = (*it)->create(op, request); if (backend) { backend->manager = this; -#ifndef QT_NO_BEARERMANAGEMENT - //copy network session down to the backend - if (networkSession) - backend->setProperty("_q_networksession", QVariant::fromValue(networkSession)); -#endif return backend; // found a factory that handled our request } ++it; @@ -374,6 +369,8 @@ bool QNetworkAccessBackend::start() if (manager->networkSession->isOpen() && manager->networkSession->state() == QNetworkSession::Connected) { + //copy network session down to the backend + setProperty("_q_networksession", QVariant::fromValue(manager->networkSession)); open(); return true; } -- cgit v0.12 From 99baeb5b6b2c6d0b2724709ae8caa789e5ad5895 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Thu, 10 Mar 2011 18:16:05 +0000 Subject: Fixes for QTcpServer autotest Set symbian capabilities in the two sub .pro files Enable IPv6 test on symbian Disable tests that use open C functions on socket descriptors When bearer management is enabled, start the network interface at start of the test. Reviewed-by: Markus Goetz --- .../qtcpserver/crashingServer/crashingServer.pro | 1 + tests/auto/qtcpserver/qtcpserver.pro | 2 -- tests/auto/qtcpserver/test/test.pro | 7 +++-- tests/auto/qtcpserver/tst_qtcpserver.cpp | 34 ++++++++++++++++++---- 4 files changed, 34 insertions(+), 10 deletions(-) diff --git a/tests/auto/qtcpserver/crashingServer/crashingServer.pro b/tests/auto/qtcpserver/crashingServer/crashingServer.pro index 0bea655..700e952 100644 --- a/tests/auto/qtcpserver/crashingServer/crashingServer.pro +++ b/tests/auto/qtcpserver/crashingServer/crashingServer.pro @@ -6,3 +6,4 @@ DESTDIR = ./ # This means the auto test works on some machines for MinGW. No dialog stalls # the application. win32-g++*:CONFIG += console +symbian: TARGET.CAPABILITY += NetworkServices ReadUserData diff --git a/tests/auto/qtcpserver/qtcpserver.pro b/tests/auto/qtcpserver/qtcpserver.pro index a3744a2..e123cfe 100644 --- a/tests/auto/qtcpserver/qtcpserver.pro +++ b/tests/auto/qtcpserver/qtcpserver.pro @@ -1,6 +1,4 @@ TEMPLATE = subdirs SUBDIRS = test crashingServer -symbian: TARGET.CAPABILITY = NetworkServices - diff --git a/tests/auto/qtcpserver/test/test.pro b/tests/auto/qtcpserver/test/test.pro index e91ba20..65e1d82 100644 --- a/tests/auto/qtcpserver/test/test.pro +++ b/tests/auto/qtcpserver/test/test.pro @@ -13,9 +13,10 @@ wince*: { } symbian { - crashApp.files = $$QT_BUILD_TREE/examples/widgets/wiggly/$${BUILD_DIR}/crashingServer.exe - crashApp.path = . - DEPLOYMENT += crashApp + crashApp.files = $$QT_BUILD_TREE/examples/widgets/wiggly/$${BUILD_DIR}/crashingServer.exe + crashApp.path = . + DEPLOYMENT += crashApp + TARGET.CAPABILITY += NetworkServices ReadUserData } TARGET = ../tst_qtcpserver diff --git a/tests/auto/qtcpserver/tst_qtcpserver.cpp b/tests/auto/qtcpserver/tst_qtcpserver.cpp index 3d377a4..cff2fe5 100644 --- a/tests/auto/qtcpserver/tst_qtcpserver.cpp +++ b/tests/auto/qtcpserver/tst_qtcpserver.cpp @@ -70,6 +70,9 @@ Q_DECLARE_METATYPE(QNetworkProxy) Q_DECLARE_METATYPE(QList) +#include +#include +#include #include "../network-settings.h" //TESTED_CLASS= @@ -86,6 +89,7 @@ public: public slots: void initTestCase_data(); + void initTestCase(); void init(); void cleanup(); private slots: @@ -107,6 +111,11 @@ private slots: void proxyFactory(); void qtbug14268_peek(); + +private: +#ifndef QT_NO_BEARERMANAGEMENT + QNetworkSession *networkSession; +#endif }; // Testing get/set functions @@ -141,6 +150,16 @@ void tst_QTcpServer::initTestCase_data() QTest::newRow("WithSocks5Proxy") << true << int(QNetworkProxy::Socks5Proxy); } +void tst_QTcpServer::initTestCase() +{ +#ifndef QT_NO_BEARERMANAGEMENT + QNetworkConfigurationManager man; + networkSession = new QNetworkSession(man.defaultConfiguration(), this); + networkSession->open(); + QVERIFY(networkSession->waitForOpened()); +#endif +} + void tst_QTcpServer::init() { QFETCH_GLOBAL(bool, setProxy); @@ -190,7 +209,7 @@ void tst_QTcpServer::clientServerLoop() QTcpSocket client; QHostAddress serverAddress = QHostAddress::LocalHost; - if (!(server.serverAddress() == QHostAddress::Any)) + if (!(server.serverAddress() == QHostAddress::Any) && !(server.serverAddress() == QHostAddress::AnyIPv6)) serverAddress = server.serverAddress(); client.connectToHost(serverAddress, server.serverPort()); @@ -222,9 +241,6 @@ void tst_QTcpServer::clientServerLoop() //---------------------------------------------------------------------------------- void tst_QTcpServer::ipv6Server() { -#if defined(Q_OS_SYMBIAN) - QSKIP("Symbian: IPv6 is not yet supported", SkipAll); -#endif //### need to enter the event loop for the server to get the connection ?? ( windows) QTcpServer server; if (!server.listen(QHostAddress::LocalHostIPv6, 8944)) { @@ -244,6 +260,8 @@ void tst_QTcpServer::ipv6Server() QTcpSocket *serverSocket = 0; QVERIFY((serverSocket = server.nextPendingConnection())); + serverSocket->close(); + delete serverSocket; } //---------------------------------------------------------------------------------- @@ -379,7 +397,8 @@ void tst_QTcpServer::setSocketDescriptor() QTcpServer server; QVERIFY(!server.setSocketDescriptor(42)); QCOMPARE(server.serverError(), QAbstractSocket::UnsupportedSocketOperationError); - +#ifndef Q_OS_SYMBIAN + //adopting Open C sockets is not supported, neither is adopting externally created RSocket #ifdef Q_OS_WIN // ensure winsock is started WSADATA wsaData; @@ -402,6 +421,7 @@ void tst_QTcpServer::setSocketDescriptor() #ifdef Q_OS_WIN WSACleanup(); #endif +#endif } //---------------------------------------------------------------------------------- @@ -493,6 +513,9 @@ void tst_QTcpServer::addressReusable() void tst_QTcpServer::setNewSocketDescriptorBlocking() { +#ifdef Q_OS_SYMBIAN + QSKIP("open C ioctls on Qt sockets not supported", SkipAll); +#else QFETCH_GLOBAL(bool, setProxy); if (setProxy) { QFETCH_GLOBAL(int, proxyType); @@ -507,6 +530,7 @@ void tst_QTcpServer::setNewSocketDescriptorBlocking() socket.connectToHost(QHostAddress::LocalHost, server.serverPort()); QVERIFY(server.waitForNewConnection(5000)); QVERIFY(server.ok); +#endif } void tst_QTcpServer::invalidProxy_data() -- cgit v0.12 From a2c9031817a7faaab62b15b8976a1c8664e108d6 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Thu, 10 Mar 2011 18:20:53 +0000 Subject: QSymbianSocketEngine - return expected error code from bind In the unix socket engine, EADDRNOTAVAIL is returned by the native call when attempting to bind to a non existant interface. On symbian, the generic KErrNotFound is returned. Specifically for bind() convert KErrNotFound to the expected error code QAbstractSocket::SocketAddressNotAvailableError which is relied on by autotest (and possibly but unlikely, existing applications) Reviewed-by: Markus Goetz --- src/network/socket/qsymbiansocketengine.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index ed7962c..491b515 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -669,7 +669,15 @@ bool QSymbianSocketEngine::bind(const QHostAddress &address, quint16 port) #endif if (err) { - d->setError(err); + switch (err) { + case KErrNotFound: + // the specified interface was not found - use the error code expected + d->setError(QAbstractSocket::SocketAddressNotAvailableError, QSymbianSocketEnginePrivate::AddressNotAvailableErrorString); + break; + default: + d->setError(err); + break; + } #if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QSymbianSocketEngine::bind(%s, %i) == false (%s)", -- cgit v0.12 From 7f75862d6e8dbfb714a04ecd5047b4ec1714a3cf Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Mon, 14 Mar 2011 15:46:59 +0100 Subject: QLocalServer: Fix compilation --- src/network/socket/qlocalserver_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/socket/qlocalserver_p.h b/src/network/socket/qlocalserver_p.h index 8ec3ef0..1ee5df2 100644 --- a/src/network/socket/qlocalserver_p.h +++ b/src/network/socket/qlocalserver_p.h @@ -65,7 +65,7 @@ # include # include #else -# include +# include # include #endif -- cgit v0.12 From 76487301421c2b127f564564e32c0c90a7b89ea2 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Mon, 14 Mar 2011 16:20:55 +0100 Subject: QSymbianSocketEngine: Compile fix --- src/network/socket/qsymbiansocketengine.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index 491b515..db98ade 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -47,7 +47,7 @@ #include "qelapsedtimer.h" #include "qvarlengtharray.h" #include "qnetworkinterface.h" -#include "qnetworksession_p.h" +#include #include #include #include -- cgit v0.12 From 479f234ec89db7e5916c27a7eac234d2ee8833c1 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 11 Mar 2011 16:21:52 +0000 Subject: Remove indirection through fake socket notifier in symbian socket engine Instead of creating socket notifiers and sending faked events to them, call the engine's notification functions directly. Reviewed-by: Markus Goetz --- src/network/socket/qsymbiansocketengine.cpp | 218 +++++++--------------------- src/network/socket/qsymbiansocketengine_p.h | 11 +- 2 files changed, 58 insertions(+), 171 deletions(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index db98ade..be04b56 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -70,8 +70,6 @@ #include #include -#define QNATIVESOCKETENGINE_DEBUG - #if defined QNATIVESOCKETENGINE_DEBUG #include #include @@ -263,9 +261,9 @@ void QSymbianSocketEnginePrivate::setPortAndAddress(TInetAddr& nativeAddr, quint QSymbianSocketEnginePrivate::QSymbianSocketEnginePrivate() : socketDescriptor(-1), socketServer(QSymbianSocketManager::instance().getSocketServer()), - readNotifier(0), - writeNotifier(0), - exceptNotifier(0), + readNotificationsEnabled(false), + writeNotificationsEnabled(false), + exceptNotificationsEnabled(false), asyncSelect(0) { } @@ -970,12 +968,9 @@ void QSymbianSocketEngine::close() qDebug("QSymbianSocketEngine::close()"); #endif - if (d->readNotifier) - d->readNotifier->setEnabled(false); - if (d->writeNotifier) - d->writeNotifier->setEnabled(false); - if (d->exceptNotifier) - d->exceptNotifier->setEnabled(false); + d->readNotificationsEnabled = false; + d->writeNotificationsEnabled = false; + d->exceptNotificationsEnabled = false; if (d->asyncSelect) { d->asyncSelect->deleteLater(); d->asyncSelect = 0; @@ -1003,18 +998,6 @@ void QSymbianSocketEngine::close() d->localAddress.clear(); d->peerPort = 0; d->peerAddress.clear(); - if (d->readNotifier) { - qDeleteInEventHandler(d->readNotifier); - d->readNotifier = 0; - } - if (d->writeNotifier) { - qDeleteInEventHandler(d->writeNotifier); - d->writeNotifier = 0; - } - if (d->exceptNotifier) { - qDeleteInEventHandler(d->exceptNotifier); - d->exceptNotifier = 0; - } } qint64 QSymbianSocketEngine::write(const char *data, qint64 len) @@ -1446,136 +1429,55 @@ void QSymbianSocketEnginePrivate::setError(TInt symbianError) hasSetSocketError = true; } -class QReadNotifier : public QSocketNotifier -{ - friend class QAsyncSelect; -public: - QReadNotifier(int fd, QSymbianSocketEngine *parent) - : QSocketNotifier(fd, QSocketNotifier::Read, parent) - { engine = parent; } -protected: - bool event(QEvent *); - - QSymbianSocketEngine *engine; -}; - -bool QReadNotifier::event(QEvent *e) -{ - if (e->type() == QEvent::SockAct) { - engine->readNotification(); - return true; - } - return QSocketNotifier::event(e); -} - bool QSymbianSocketEngine::isReadNotificationEnabled() const { Q_D(const QSymbianSocketEngine); Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::isReadNotificationEnabled(), false); - return d->readNotifier && d->readNotifier->isEnabled(); + return d->readNotificationsEnabled; } void QSymbianSocketEngine::setReadNotificationEnabled(bool enable) { Q_D(QSymbianSocketEngine); Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setReadNotificationEnabled(), Q_VOID); - if (d->readNotifier) { - d->readNotifier->setEnabled(enable); - } else if (enable && d->threadData->eventDispatcher) { - QReadNotifier *rn = new QReadNotifier(d->socketDescriptor, this); - d->readNotifier = rn; - if (!d->asyncSelect) - d->asyncSelect = q_check_ptr(new QAsyncSelect(0, d->nativeSocket, this)); - d->asyncSelect->setReadNotifier(rn); - d->readNotifier->setEnabled(true); - } +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug() << "QSymbianSocketEngine::setReadNotificationEnabled" << enable << "socket" << d->socketDescriptor; +#endif + d->readNotificationsEnabled = enable; + if (enable && d->threadData->eventDispatcher && !d->asyncSelect) + d->asyncSelect = q_check_ptr(new QAsyncSelect(0, d->nativeSocket, this)); // TODO: what do we do if event dispatcher doesn't exist yet? if (d->asyncSelect) d->asyncSelect->IssueRequest(); } - -class QWriteNotifier : public QSocketNotifier -{ - friend class QAsyncSelect; -public: - QWriteNotifier(int fd, QSymbianSocketEngine *parent) - : QSocketNotifier(fd, QSocketNotifier::Write, parent) - { engine = parent; } -protected: - bool event(QEvent *); - - QSymbianSocketEngine *engine; -}; - -bool QWriteNotifier::event(QEvent *e) -{ - if (e->type() == QEvent::SockAct) { - if (engine->state() == QAbstractSocket::ConnectingState) - engine->connectionNotification(); - else - engine->writeNotification(); - return true; - } - return QSocketNotifier::event(e); -} - bool QSymbianSocketEngine::isWriteNotificationEnabled() const { Q_D(const QSymbianSocketEngine); Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::isWriteNotificationEnabled(), false); - return d->writeNotifier && d->writeNotifier->isEnabled(); + return d->writeNotificationsEnabled; } void QSymbianSocketEngine::setWriteNotificationEnabled(bool enable) { Q_D(QSymbianSocketEngine); Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setWriteNotificationEnabled(), Q_VOID); - if (d->writeNotifier) { - d->writeNotifier->setEnabled(enable); - } else if (enable && d->threadData->eventDispatcher) { - QWriteNotifier *wn = new QWriteNotifier(d->socketDescriptor, this); - d->writeNotifier = wn; - if (!(d->asyncSelect)) - d->asyncSelect = q_check_ptr(new QAsyncSelect(d->threadData->eventDispatcher, d->nativeSocket, this)); - d->asyncSelect->setWriteNotifier(wn); - d->writeNotifier->setEnabled(true); - } +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug() << "QSymbianSocketEngine::setWriteNotificationEnabled" << enable << "socket" << d->socketDescriptor; +#endif + d->writeNotificationsEnabled = enable; + if (enable && d->threadData->eventDispatcher && !d->asyncSelect) + d->asyncSelect = q_check_ptr(new QAsyncSelect(0, d->nativeSocket, this)); // TODO: what do we do if event dispatcher doesn't exist yet? if (d->asyncSelect) d->asyncSelect->IssueRequest(); } -class QExceptionNotifier : public QSocketNotifier -{ - friend class QAsyncSelect; -public: - QExceptionNotifier(int fd, QSymbianSocketEngine *parent) - : QSocketNotifier(fd, QSocketNotifier::Exception, parent) { engine = parent; } - -protected: - bool event(QEvent *); - - QSymbianSocketEngine *engine; -}; - -bool QExceptionNotifier::event(QEvent *e) -{ - if (e->type() == QEvent::SockAct) { - if (engine->state() == QAbstractSocket::ConnectingState) - engine->connectionNotification(); - else - engine->exceptionNotification(); - return true; - } - return QSocketNotifier::event(e); -} - bool QSymbianSocketEngine::isExceptionNotificationEnabled() const { Q_D(const QSymbianSocketEngine); Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::isExceptionNotificationEnabled(), false); - return d->exceptNotifier && d->exceptNotifier->isEnabled(); + return d->exceptNotificationsEnabled; return false; } @@ -1584,16 +1486,12 @@ void QSymbianSocketEngine::setExceptionNotificationEnabled(bool enable) { Q_D(QSymbianSocketEngine); Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::setExceptionNotificationEnabled(), Q_VOID); - if (d->exceptNotifier) { - d->exceptNotifier->setEnabled(enable); - } else if (enable && d->threadData->eventDispatcher) { - QExceptionNotifier *en = new QExceptionNotifier(d->socketDescriptor, this); - d->exceptNotifier = en; - if (!(d->asyncSelect)) - d->asyncSelect = q_check_ptr(new QAsyncSelect(d->threadData->eventDispatcher, d->nativeSocket, this)); - d->asyncSelect->setExceptionNotifier(en); - d->writeNotifier->setEnabled(true); - } +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug() << "QSymbianSocketEngine::setExceptionNotificationEnabled" << enable << "socket" << d->socketDescriptor; +#endif + d->exceptNotificationsEnabled = enable; + if (enable && d->threadData->eventDispatcher && !d->asyncSelect) + d->asyncSelect = q_check_ptr(new QAsyncSelect(0, d->nativeSocket, this)); if (d->asyncSelect) d->asyncSelect->IssueRequest(); } @@ -1692,7 +1590,7 @@ bool QSymbianSocketEngine::event(QEvent* ev) switch (ev->type()) { case QEvent::ThreadChange: #ifdef QNATIVESOCKETENGINE_DEBUG - qDebug() << "ThreadChange"; + qDebug() << "ThreadChange" << d->readNotificationsEnabled << d->writeNotificationsEnabled << d->exceptNotificationsEnabled; #endif if (d->asyncSelect) { delete d->asyncSelect; @@ -1704,22 +1602,11 @@ bool QSymbianSocketEngine::event(QEvent* ev) return true; case PostThreadChangeEvent: #ifdef QNATIVESOCKETENGINE_DEBUG - qDebug() << "PostThreadChangeEvent"; + qDebug() << "PostThreadChangeEvent" << d->readNotificationsEnabled << d->writeNotificationsEnabled << d->exceptNotificationsEnabled; #endif // recreate select in new thread d->asyncSelect = q_check_ptr(new QAsyncSelect(0, d->nativeSocket, this)); - if (d->readNotifier) { - d->asyncSelect->setReadNotifier(static_cast(d->readNotifier)); - setReadNotificationEnabled(d->readNotifier->isEnabled()); - } - if (d->writeNotifier) { - d->asyncSelect->setWriteNotifier(static_cast(d->writeNotifier)); - setReadNotificationEnabled(d->writeNotifier->isEnabled()); - } - if (d->exceptNotifier) { - d->asyncSelect->setExceptionNotifier(static_cast(d->exceptNotifier)); - setReadNotificationEnabled(d->exceptNotifier->isEnabled()); - } + d->asyncSelect->IssueRequest(); return true; } return QAbstractSocketEngine::event(ev); @@ -1758,11 +1645,10 @@ TInt QAsyncSelect::RunError(TInt aError) if (engine) { QT_TRY { engine->d_func()->setError(aError); - QEvent e(QEvent::SockAct); - if (iExcN) - iExcN->event(&e); - if (iReadN) - iReadN->event(&e); + if (engine->isExceptionNotificationEnabled()) + engine->exceptionNotification(); + if (engine->isReadNotificationEnabled()) + engine->readNotification(); } QT_CATCH(...) {} } @@ -1781,17 +1667,20 @@ void QAsyncSelect::run() m_selectBuf() &= m_selectFlags; //the select ioctl reports everything, so mask to only what we requested //KSockSelectReadContinuation is for reading datagrams in a mode that doesn't discard when the //datagram is larger than the read buffer - Qt doesn't need to use this. - if (iReadN && ((m_selectBuf() & KSockSelectRead) || iStatus != KErrNone)) { - QEvent e(QEvent::SockAct); - iReadN->event(&e); + if (engine && engine->isReadNotificationEnabled() + && ((m_selectBuf() & KSockSelectRead) || iStatus != KErrNone)) { + engine->readNotification(); } - if (iWriteN && ((m_selectBuf() & KSockSelectWrite) || iStatus != KErrNone)) { - QEvent e(QEvent::SockAct); - iWriteN->event(&e); + if (engine && engine->isWriteNotificationEnabled() + && ((m_selectBuf() & KSockSelectWrite) || iStatus != KErrNone)) { + if (engine->state() == QAbstractSocket::ConnectingState) + engine->connectionNotification(); + else + engine->writeNotification(); } - if (iExcN && ((m_selectBuf() & KSockSelectExcept) || iStatus != KErrNone)) { - QEvent e(QEvent::SockAct); - iExcN->event(&e); + if (engine && engine->isExceptionNotificationEnabled() + && ((m_selectBuf() & KSockSelectExcept) || iStatus != KErrNone)) { + engine->exceptionNotification(); } m_inSocketEvent = false; if (m_deleteLater) { @@ -1805,9 +1694,6 @@ void QAsyncSelect::run() void QAsyncSelect::deleteLater() { if (m_inSocketEvent) { - iExcN = 0; - iReadN = 0; - iWriteN = 0; engine = 0; m_deleteLater = true; } else { @@ -1820,13 +1706,16 @@ void QAsyncSelect::IssueRequest() if (m_inSocketEvent) return; //prevent thrashing during a callback - socket engine enables/disables multiple notifiers TUint selectFlags = 0; - if (iReadN && iReadN->isEnabled()) + if (engine->isReadNotificationEnabled()) selectFlags |= KSockSelectRead; - if (iWriteN && iWriteN->isEnabled()) + if (engine->isWriteNotificationEnabled()) selectFlags |= KSockSelectWrite; - if (iExcN && iExcN->isEnabled()) + if (engine->isExceptionNotificationEnabled()) selectFlags |= KSockSelectExcept; if (selectFlags != m_selectFlags) { +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug() << "QAsyncSelect::IssueRequest() - select flags" << m_selectFlags << "->" << selectFlags; +#endif Cancel(); m_selectFlags = selectFlags; } @@ -1836,6 +1725,9 @@ void QAsyncSelect::IssueRequest() m_socket.Ioctl(KIOctlSelect, iStatus, &m_selectBuf, KSOLSocket); SetActive(); } +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug() << "QAsyncSelect::IssueRequest() - IsActive" << IsActive(); +#endif } QT_END_NAMESPACE diff --git a/src/network/socket/qsymbiansocketengine_p.h b/src/network/socket/qsymbiansocketengine_p.h index bc39450..432e4dc 100644 --- a/src/network/socket/qsymbiansocketengine_p.h +++ b/src/network/socket/qsymbiansocketengine_p.h @@ -162,10 +162,6 @@ public: void refresh(); - void setReadNotifier(QReadNotifier *rn) { iReadN = rn; } - void setWriteNotifier(QWriteNotifier *wn) { iWriteN = wn; } - void setExceptionNotifier(QExceptionNotifier *en) { iExcN = en; } - protected: void DoCancel(); void RunL(); @@ -173,9 +169,6 @@ protected: TInt RunError(TInt aError); private: - QReadNotifier* iReadN; - QWriteNotifier* iWriteN; - QExceptionNotifier* iExcN; bool m_inSocketEvent; bool m_deleteLater; RSocket &m_socket; @@ -198,7 +191,9 @@ public: RSocketServ& socketServer; mutable RTimer selectTimer; - QSocketNotifier *readNotifier, *writeNotifier, *exceptNotifier; + bool readNotificationsEnabled; + bool writeNotificationsEnabled; + bool exceptNotificationsEnabled; QAsyncSelect* asyncSelect; // FIXME this is duplicated from qnativesocketengine_p.h -- cgit v0.12 From 230ef5e3ad8bb4dadef7dbf2c8bf41156bf30130 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 11 Mar 2011 16:59:48 +0000 Subject: tst_QNetworkReply::ioGetFromBuiltinHttp issues The https:limited subtest was too slow and didn't fail in the expected place (it was expected to be too fast) Both limited test cases timed out when debug enabled in the socket engine, so the timeout is increased from 11->30 seconds Reviewed-by: Markus Goetz --- tests/auto/qnetworkreply/tst_qnetworkreply.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp index 7fde3f8..ffe7ea4 100644 --- a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp @@ -3846,7 +3846,7 @@ void tst_QNetworkReply::ioGetFromBuiltinHttp() connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); QTime loopTime; loopTime.start(); - QTestEventLoop::instance().enterLoop(11); + QTestEventLoop::instance().enterLoop(30); const int elapsedTime = loopTime.elapsed(); server.wait(); reader.wrapUp(); @@ -3878,10 +3878,9 @@ void tst_QNetworkReply::ioGetFromBuiltinHttp() const int minRate = rate * 1024 * (100-allowedDeviation) / 100; const int maxRate = rate * 1024 * (100+allowedDeviation) / 100; qDebug() << minRate << "<="<< server.transferRate << "<=" << maxRate << "?"; - QVERIFY(server.transferRate >= minRate); QEXPECT_FAIL("http+limited", "Limiting is broken right now, check QTBUG-15065", Continue); QEXPECT_FAIL("https+limited", "Limiting is broken right now, check QTBUG-15065", Continue); - QVERIFY(server.transferRate <= maxRate); + QVERIFY(server.transferRate >= minRate && server.transferRate <= maxRate); } } -- cgit v0.12 From b24711c377d5d0eab17d729d3d1291771410b846 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 11 Mar 2011 19:19:07 +0000 Subject: Fix capabilities in qtpcsocket autotest Moved from the subdirs pro file to the executable pro files. Reviewed-by: Markus Goetz --- tests/auto/qtcpsocket/qtcpsocket.pro | 1 - tests/auto/qtcpsocket/stressTest/stressTest.pro | 1 + tests/auto/qtcpsocket/test/test.pro | 5 ++++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/auto/qtcpsocket/qtcpsocket.pro b/tests/auto/qtcpsocket/qtcpsocket.pro index 8b1f664..5dfff5b 100644 --- a/tests/auto/qtcpsocket/qtcpsocket.pro +++ b/tests/auto/qtcpsocket/qtcpsocket.pro @@ -6,4 +6,3 @@ wince*|symbian|vxworks* : SUBDIRS = test requires(contains(QT_CONFIG,private_tests)) -symbian: TARGET.CAPABILITY = NetworkServices diff --git a/tests/auto/qtcpsocket/stressTest/stressTest.pro b/tests/auto/qtcpsocket/stressTest/stressTest.pro index 9a653c6..adf0217 100644 --- a/tests/auto/qtcpsocket/stressTest/stressTest.pro +++ b/tests/auto/qtcpsocket/stressTest/stressTest.pro @@ -9,4 +9,5 @@ DESTDIR = ./ MOC_DIR = .moc/ TMP_DIR = .tmp/ +symbian: TARGET.CAPABILITY = NetworkServices diff --git a/tests/auto/qtcpsocket/test/test.pro b/tests/auto/qtcpsocket/test/test.pro index 5dde565..f4207d6 100644 --- a/tests/auto/qtcpsocket/test/test.pro +++ b/tests/auto/qtcpsocket/test/test.pro @@ -11,7 +11,10 @@ wince*: { QT += network vxworks:QT -= gui -symbian: TARGET.EPOCHEAPSIZE="0x100 0x3000000" +symbian: { + TARGET.EPOCHEAPSIZE="0x100 0x3000000" + TARGET.CAPABILITY = NetworkServices +} TARGET = tst_qtcpsocket -- cgit v0.12 From cec4faf5b0eb2d5f55c4651c1a8e6137808c21c7 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 11 Mar 2011 19:40:32 +0000 Subject: Fix for server.listen getting IPv6 address Reviewed-by: Markus Goetz --- tests/auto/qtcpsocket/tst_qtcpsocket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/qtcpsocket/tst_qtcpsocket.cpp b/tests/auto/qtcpsocket/tst_qtcpsocket.cpp index b972130..6852e29 100644 --- a/tests/auto/qtcpsocket/tst_qtcpsocket.cpp +++ b/tests/auto/qtcpsocket/tst_qtcpsocket.cpp @@ -1432,7 +1432,7 @@ void tst_QTcpSocket::dontCloseOnTimeout() QVERIFY(server.listen()); QHostAddress serverAddress = QHostAddress::LocalHost; - if (!(server.serverAddress() == QHostAddress::Any)) + if (!(server.serverAddress() == QHostAddress::Any) && !(server.serverAddress() == QHostAddress::AnyIPv6)) serverAddress = server.serverAddress(); QTcpSocket *socket = newSocket(); -- cgit v0.12 From 76a18d2eab6b94929f79dc0c4bec59caaaa8d270 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 14 Mar 2011 16:17:10 +0000 Subject: Enable IPv6 test in QNetworkInterface autotest IPv6 test was skipped for symbian, now enabled it. Also start the default bearer before testing, so there are interfaces other than loopback available to test. Reviewed-by: Markus Goetz --- .../qnetworkinterface/tst_qnetworkinterface.cpp | 38 ++++++++++++++++++---- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/tests/auto/qnetworkinterface/tst_qnetworkinterface.cpp b/tests/auto/qnetworkinterface/tst_qnetworkinterface.cpp index 0d7c68e..c630eca 100644 --- a/tests/auto/qnetworkinterface/tst_qnetworkinterface.cpp +++ b/tests/auto/qnetworkinterface/tst_qnetworkinterface.cpp @@ -45,6 +45,8 @@ #include #include #include +#include +#include #include "../network-settings.h" //TESTED_FILES=qnetworkinterface.cpp qnetworkinterface.h qnetworkinterface_unix.cpp qnetworkinterface_win.cpp @@ -58,23 +60,52 @@ public: virtual ~tst_QNetworkInterface(); private slots: + void initTestCase(); + void cleanupTestCase(); void dump(); void loopbackIPv4(); void loopbackIPv6(); void localAddress(); void interfaceFromXXX(); void copyInvalidInterface(); + +private: +#ifndef QT_NO_BEARER_MANAGEMENT + QNetworkConfigurationManager *netConfMan; + QNetworkConfiguration networkConfiguration; + QScopedPointer networkSession; +#endif }; tst_QNetworkInterface::tst_QNetworkInterface() { - Q_SET_DEFAULT_IAP } tst_QNetworkInterface::~tst_QNetworkInterface() { } +void tst_QNetworkInterface::initTestCase() +{ +#ifndef QT_NO_BEARERMANAGEMENT + netConfMan = new QNetworkConfigurationManager(this); + networkConfiguration = netConfMan->defaultConfiguration(); + networkSession.reset(new QNetworkSession(networkConfiguration)); + if (!networkSession->isOpen()) { + networkSession->open(); + QVERIFY(networkSession->waitForOpened(30000)); + } +#endif +} + +void tst_QNetworkInterface::cleanupTestCase() +{ +#ifndef QT_NO_BEARERMANAGEMENT + if (networkSession && networkSession->isOpen()) { + networkSession->close(); + } +#endif +} void tst_QNetworkInterface::dump() { @@ -127,10 +158,6 @@ void tst_QNetworkInterface::loopbackIPv4() void tst_QNetworkInterface::loopbackIPv6() { -#ifdef Q_OS_SYMBIAN - QSKIP( "Symbian: IPv6 is not yet supported", SkipAll ); -#else - QList all = QNetworkInterface::allAddresses(); bool loopbackfound = false; @@ -144,7 +171,6 @@ void tst_QNetworkInterface::loopbackIPv6() anyIPv6 = true; QVERIFY(!anyIPv6 || loopbackfound); -#endif } void tst_QNetworkInterface::localAddress() -- cgit v0.12 From 981ca30f216b4655b4c171aba5bcb37890cb92b1 Mon Sep 17 00:00:00 2001 From: Martin Petersson Date: Tue, 15 Mar 2011 12:25:28 +0100 Subject: SSL: fix compilation on Windows Reviewed-by: Markus Goetz --- src/network/ssl/qsslsocket_p.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/network/ssl/qsslsocket_p.h b/src/network/ssl/qsslsocket_p.h index 7b92f95..4662c56 100644 --- a/src/network/ssl/qsslsocket_p.h +++ b/src/network/ssl/qsslsocket_p.h @@ -73,6 +73,7 @@ QT_BEGIN_NAMESPACE typedef OSStatus (*PtrSecTrustSettingsCopyCertificates)(int, CFArrayRef*); typedef OSStatus (*PtrSecTrustCopyAnchorCertificates)(CFArrayRef*); #elif defined(Q_OS_WIN) +#include #include #ifndef HCRYPTPROV_LEGACY #define HCRYPTPROV_LEGACY HCRYPTPROV -- cgit v0.12 From 86b1e68285a4dae855a5826f76728cee347d1af2 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Tue, 15 Mar 2011 15:21:39 +0100 Subject: tst_qhostinfo: Fixes Reviewed-by: Peter Hartmann --- tests/auto/qhostinfo/tst_qhostinfo.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/auto/qhostinfo/tst_qhostinfo.cpp b/tests/auto/qhostinfo/tst_qhostinfo.cpp index ee2fe0d..8be8dcb 100644 --- a/tests/auto/qhostinfo/tst_qhostinfo.cpp +++ b/tests/auto/qhostinfo/tst_qhostinfo.cpp @@ -291,6 +291,7 @@ void tst_QHostInfo::lookupIPv6_data() QTest::addColumn("err"); QTest::newRow("ip6") << "www.ipv6-net.org" << "62.93.217.177 2001:618:1401:0:0:0:0:4" << int(QHostInfo::NoError); + QTest::newRow("ip6") << "ipv6.google.com" << "2A00:1450:8007:0:0:0:0:63" << int(QHostInfo::NoError); // avoid using real IPv6 addresses here because this will do a DNS query // real addresses are between 2000:: and 3fff:ffff:ffff:ffff:ffff:ffff:ffff @@ -337,7 +338,7 @@ void tst_QHostInfo::reverseLookup_data() // ### Use internal DNS instead. Discussed with Andreas. //QTest::newRow("classical.hexago.com") << QString("2001:5c0:0:2::24") << QStringList(QString("classical.hexago.com")) << 0; - QTest::newRow("origin.cisco.com") << QString("12.159.148.94") << QStringList(QString("origin.cisco.com")) << 0; + QTest::newRow("gitorious.org") << QString("87.238.52.168") << QStringList(QString("gitorious.org")) << 0; QTest::newRow("bogus-name") << QString("1::2::3::4") << QStringList() << 1; } -- cgit v0.12 From 59c7740c9d45a88713db20efbfcfbdaf3873b60c Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 15 Mar 2011 18:47:11 +0000 Subject: Make creating sockets with an explicit network session thread safe Added a mutex to QNetworkSessionPrivate Lock the mutex in the symbian bearer plugin for functions that change the validity of the RConnection. Added factory functions to open an RSocket or RHostResolver, which lock the mutex before the esock function calls. If there is no RConnection, then KErrNotReady is returned (the same as when there is an RConnection but it has not been started). Task-number: QTBUG-18143 Reviewed-by: Markus Goetz --- src/network/bearer/qnetworksession.cpp | 31 ++++++++++++++++++++++ src/network/bearer/qnetworksession_p.h | 9 +++++++ src/network/socket/qsymbiansocketengine.cpp | 14 +++------- .../bearer/symbian/qnetworksession_impl.cpp | 3 +++ 4 files changed, 46 insertions(+), 11 deletions(-) diff --git a/src/network/bearer/qnetworksession.cpp b/src/network/bearer/qnetworksession.cpp index 6106550..21e64d9 100644 --- a/src/network/bearer/qnetworksession.cpp +++ b/src/network/bearer/qnetworksession.cpp @@ -44,10 +44,16 @@ #include #include +#include #include "qnetworkconfigmanager_p.h" #include "qnetworksession_p.h" +#ifdef Q_OS_SYMBIAN +#include +#include +#endif + #ifndef QT_NO_BEARERMANAGEMENT QT_BEGIN_NAMESPACE @@ -710,8 +716,33 @@ RConnection* QNetworkSessionPrivate::nativeSession(QNetworkSession &s) { if (!s.d) return 0; + if (s.thread() != QThread::currentThread()) + qWarning("QNetworkSessionPrivate::nativeSession called in wrong thread"); return s.d->nativeSession(); } + +TInt QNetworkSessionPrivate::nativeOpenSocket(QNetworkSession& s, RSocket& sock, TUint family, TUint type, TUint protocol) +{ + if (!s.d) + return 0; + QMutexLocker lock(&(s.d->mutex)); + RConnection *con = s.d->nativeSession(); + if (!con || !con->SubSessionHandle()) + return KErrNotReady; + return sock.Open(qt_symbianGetSocketServer(), family, type, protocol, *con); +} + +TInt QNetworkSessionPrivate::nativeOpenHostResolver(QNetworkSession& s, RHostResolver& resolver, TUint family, TUint protocol) +{ + if (!s.d) + return 0; + QMutexLocker lock(&(s.d->mutex)); + RConnection *con = s.d->nativeSession(); + if (!con || !con->SubSessionHandle()) + return KErrNotReady; + return resolver.Open(qt_symbianGetSocketServer(), family, protocol, *con); +} + #endif #include "moc_qnetworksession.cpp" diff --git a/src/network/bearer/qnetworksession_p.h b/src/network/bearer/qnetworksession_p.h index e2fcfe6..b359f80 100644 --- a/src/network/bearer/qnetworksession_p.h +++ b/src/network/bearer/qnetworksession_p.h @@ -61,6 +61,8 @@ #ifdef Q_OS_SYMBIAN class RConnection; +class RSocket; +class RHostResolver; #endif QT_BEGIN_NAMESPACE @@ -108,8 +110,13 @@ public: virtual quint64 activeTime() const = 0; #ifdef Q_OS_SYMBIAN + // get internal RConnection (not thread safe, call only from thread that owns the QNetworkSession) static RConnection* nativeSession(QNetworkSession&); virtual RConnection* nativeSession() = 0; + // open socket using the internal RConnection (thread safe) + static TInt nativeOpenSocket(QNetworkSession& session, RSocket& socket, TUint family, TUint type, TUint protocol); + // open host resolver using the internal RConnection (thread safe) + static TInt nativeOpenHostResolver(QNetworkSession& session, RHostResolver& resolver, TUint family, TUint protocol); #endif protected: inline QNetworkConfigurationPrivatePointer privateConfiguration(const QNetworkConfiguration &config) const @@ -150,6 +157,8 @@ protected: QNetworkSession::State state; bool isOpen; + + QMutex mutex; }; QT_END_NAMESPACE diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index be04b56..688f724 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -189,21 +189,13 @@ bool QSymbianSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType so //Check if there is a user specified session RConnection *connection = 0; QVariant v(q->property("_q_networksession")); + TInt err; if (v.isValid()) { QSharedPointer s = qvariant_cast >(v); - connection = QNetworkSessionPrivate::nativeSession(*s); + err = QNetworkSessionPrivate::nativeOpenSocket(*s, nativeSocket, family, type, protocol); #ifdef QNATIVESOCKETENGINE_DEBUG - qDebug() << "QSymbianSocketEnginePrivate::createNewSocket - _q_networksession was set" << connection; + qDebug() << "QSymbianSocketEnginePrivate::createNewSocket - _q_networksession was set" << err; #endif - } - TInt err; - if (connection) { - if (connection->SubSessionHandle()) - err = nativeSocket.Open(socketServer, family, type, protocol, *connection); - else { - setError(QAbstractSocket::NetworkError, SessionNotOpenErrorString); - return false; - } } else err = nativeSocket.Open(socketServer, family, type, protocol); //TODO: FIXME - deprecated API, make sure we always have a connection instead diff --git a/src/plugins/bearer/symbian/qnetworksession_impl.cpp b/src/plugins/bearer/symbian/qnetworksession_impl.cpp index 5325293..a9bd414 100644 --- a/src/plugins/bearer/symbian/qnetworksession_impl.cpp +++ b/src/plugins/bearer/symbian/qnetworksession_impl.cpp @@ -76,6 +76,7 @@ QNetworkSessionPrivateImpl::QNetworkSessionPrivateImpl(SymbianEngine *engine) void QNetworkSessionPrivateImpl::closeHandles() { + QMutexLocker lock(&mutex); // Cancel Connection Progress Notifications first. // Note: ConnectionNotifier must be destroyed before RConnection::Close() // => deleting ipConnectionNotifier results RConnection::CancelProgressNotification() @@ -317,6 +318,7 @@ QNetworkSession::SessionError QNetworkSessionPrivateImpl::error() const void QNetworkSessionPrivateImpl::open() { + QMutexLocker lock(&mutex); #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "open() called, session state is: " << state << " and isOpen is: " @@ -526,6 +528,7 @@ void QNetworkSessionPrivateImpl::close(bool allowSignals) void QNetworkSessionPrivateImpl::stop() { + QMutexLocker lock(&mutex); #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "stop() called, session state is: " << state << " and isOpen is : " -- cgit v0.12 From 8f239f0b0cb7faa580ba66197f56fb3d8109aaf7 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Wed, 16 Mar 2011 13:00:43 +0000 Subject: Implement IPv6 in symbian QNetworkInterface For IPv6 interfaces, the network mask is reported correctly, so we use that. For IPv4 interfaces, the network mask is reported as 0.0.0.0 so the existing workaround to get the netmask from routes is used. For loopback interfaces, the mask can be statically determined. Skip checking the routes if proper masks were reported for all the interfaces. Added a helper function for converting TInetAddr -> QHostAddress using the constructors that take binary data. (better than conversion to/from strings) Task-number: QTBUG-18137 Reviewed-by: Markus Goetz --- src/network/kernel/qnetworkinterface_symbian.cpp | 128 +++++++++++++++-------- 1 file changed, 83 insertions(+), 45 deletions(-) diff --git a/src/network/kernel/qnetworkinterface_symbian.cpp b/src/network/kernel/qnetworkinterface_symbian.cpp index 42a041c..7767f54 100644 --- a/src/network/kernel/qnetworkinterface_symbian.cpp +++ b/src/network/kernel/qnetworkinterface_symbian.cpp @@ -67,10 +67,24 @@ static QNetworkInterface::InterfaceFlags convertFlags(const TSoInetInterfaceInfo return flags; } +//TODO: share this, at least QHostInfo needs to do the same thing +static QHostAddress qt_QHostAddressFromTInetAddr(const TInetAddr& addr) +{ + //TODO: do we want to call v4 mapped addresses v4 or v6 outside of this file? + if (addr.IsV4Mapped() || addr.Family() == KAfInet) { + //convert v4 host address + return QHostAddress(addr.Address()); + } else { + //convert v6 host address + return QHostAddress((quint8 *)(addr.Ip6Address().u.iAddr8)); + } +} + static QList interfaceListing() { TInt err(KErrNone); QList interfaces; + QList addressesWithEstimatedNetmasks; // Open dummy socket for interface queries RSocket socket; @@ -90,8 +104,7 @@ static QList interfaceListing() TPckgBuf infoPckg; TSoInetInterfaceInfo &info = infoPckg(); while (socket.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, infoPckg) == KErrNone) { - // Do not include IPv6 addresses because netmask and broadcast address cannot be determined correctly - if (info.iName != KNullDesC && info.iAddress.IsV4Mapped()) { + if (info.iName != KNullDesC) { TName address; QNetworkAddressEntry entry; QNetworkInterfacePrivate *iface = 0; @@ -113,40 +126,58 @@ static QList interfaceListing() } // Get the address of the interface - info.iAddress.Output(address); - entry.setIp(QHostAddress(qt_TDesC2QString(address))); + entry.setIp(qt_QHostAddressFromTInetAddr(info.iAddress)); + +#if defined(QNETWORKINTERFACE_DEBUG) + qDebug() << "address is" << info.iAddress.Family() << entry.ip(); + qDebug() << "netmask is" << info.iNetMask.Family() << qt_QHostAddressFromTInetAddr( info.iNetMask ); +#endif // Get the interface netmask - // For some reason netmask is always 0.0.0.0 - // info.iNetMask.Output(address); - // entry.setNetmask( QHostAddress( qt_TDesC2QString( address ) ) ); - - // Workaround: Let Symbian determine netmask based on IP address class - // TODO: Works only for IPv4 - Task: 259128 Implement IPv6 support - TInetAddr netmask; - netmask.NetMask(info.iAddress); - netmask.Output(address); - entry.setNetmask(QHostAddress(qt_TDesC2QString(address))); - - // Get the interface broadcast address - if (iface->flags & QNetworkInterface::CanBroadcast) { - // For some reason broadcast address is always 0.0.0.0 - // info.iBrdAddr.Output(address); - // entry.setBroadcast( QHostAddress( qt_TDesC2QString( address ) ) ); - - // Workaround: Let Symbian determine broadcast address based on IP address - // TODO: Works only for IPv4 - Task: 259128 Implement IPv6 support - TInetAddr broadcast; - broadcast.NetBroadcast(info.iAddress); - broadcast.Output(address); - entry.setBroadcast(QHostAddress(qt_TDesC2QString(address))); + if (info.iNetMask.IsUnspecified()) { + // For some reason netmask is always 0.0.0.0 for IPv4 interfaces + // and loopback interfaces (which we statically know) + if (info.iAddress.IsV4Mapped()) { + if (info.iFeatures & KIfIsLoopback) { + entry.setPrefixLength(32); + } else { + // Workaround: Let Symbian determine netmask based on IP address class (IPv4 only API) + TInetAddr netmask; + netmask.NetMask(info.iAddress); + entry.setNetmask(QHostAddress(netmask.Address())); //binary convert v4 address + addressesWithEstimatedNetmasks << entry.ip(); +#if defined(QNETWORKINTERFACE_DEBUG) + qDebug() << "address class determined netmask" << entry.netmask(); +#endif + } + } else { + // For IPv6 interfaces + if (info.iFeatures & KIfIsLoopback) { + entry.setPrefixLength(128); + } else if (info.iNetMask.IsUnspecified()) { + //Don't see this error for IPv6, but try to handle it if it happens + entry.setPrefixLength(64); //most common +#if defined(QNETWORKINTERFACE_DEBUG) + qDebug() << "total guess netmask" << entry.netmask(); +#endif + addressesWithEstimatedNetmasks << entry.ip(); + } + } + } else { + //Expected code path for IPv6 non loopback interfaces (IPv4 could come here if symbian is fixed) + entry.setNetmask(qt_QHostAddressFromTInetAddr(info.iNetMask)); +#if defined(QNETWORKINTERFACE_DEBUG) + qDebug() << "reported netmask" << entry.netmask(); +#endif } + // broadcast address is determined from the netmask in postProcess() + // Add new entry to interface address entries iface->addressEntries << entry; #if defined(QNETWORKINTERFACE_DEBUG) - printf("\n Found network interface %s, interface flags:\n\ + qDebug("\n Found network interface %s, interface flags:\n\ IsUp = %d, IsRunning = %d, CanBroadcast = %d,\n\ IsLoopBack = %d, IsPointToPoint = %d, CanMulticast = %d, \n\ ip = %s, netmask = %s, broadcast = %s,\n\ @@ -160,8 +191,14 @@ static QList interfaceListing() } } + // if we didn't have to guess any netmasks, then we're done. + if (addressesWithEstimatedNetmasks.isEmpty()) { + socket.Close(); + return interfaces; + } + // we will try to use routing info to detect more precisely - // netmask and then ::postProcess() should calculate + // estimated netmasks and then ::postProcess() should calculate // broadcast addresses // use dummy socket to start enumerating routes @@ -176,16 +213,21 @@ static QList interfaceListing() TSoInetRouteInfo routeInfo; TPckg routeInfoPkg(routeInfo); while (socket.GetOpt(KSoInetNextRoute, KSolInetRtCtrl, routeInfoPkg) == KErrNone) { - TName address; - // get interface address - routeInfo.iIfAddr.Output(address); - QHostAddress ifAddr(qt_TDesC2QString(address)); + QHostAddress ifAddr(qt_QHostAddressFromTInetAddr(routeInfo.iIfAddr)); if (ifAddr.isNull()) continue; + if (!addressesWithEstimatedNetmasks.contains(ifAddr)) { +#if defined(QNETWORKINTERFACE_DEBUG) + qDebug() << "skipping route from" << ifAddr << "because it wasn't an estimated netmask"; +#endif + continue; + } - routeInfo.iDstAddr.Output(address); - QHostAddress destination(qt_TDesC2QString(address)); + QHostAddress destination(qt_QHostAddressFromTInetAddr(routeInfo.iDstAddr)); +#if defined(QNETWORKINTERFACE_DEBUG) + qDebug() << "route from" << ifAddr << "to" << destination; +#endif if (destination.isNull() || destination != ifAddr) continue; @@ -196,17 +238,13 @@ static QList interfaceListing() QNetworkAddressEntry entry = iface->addressEntries.at(eindex); if (entry.ip() != ifAddr) { continue; - } else if (entry.ip().protocol() != QAbstractSocket::IPv4Protocol) { - // skip if not IPv4 address (e.g. IPv6) - // as results not reliable on Symbian - continue; - } else { - routeInfo.iNetMask.Output(address); - QHostAddress netmask(qt_TDesC2QString(address)); + } else if (!routeInfo.iNetMask.IsUnspecified()) { + //the route may also return 0.0.0.0 netmask, in which case don't use it. + QHostAddress netmask(qt_QHostAddressFromTInetAddr(routeInfo.iNetMask)); entry.setNetmask(netmask); - // NULL boradcast address for - // ::postProcess to have effect - entry.setBroadcast(QHostAddress()); +#if defined(QNETWORKINTERFACE_DEBUG) + qDebug() << " - route netmask" << routeInfo.iNetMask.Family() << netmask << " (using route determined netmask)"; +#endif iface->addressEntries.replace(eindex, entry); } } -- cgit v0.12 From 6f7076d6fe80f656d8d2f7f1b005dc138b05bef3 Mon Sep 17 00:00:00 2001 From: Aaron Tunney Date: Wed, 9 Mar 2011 14:26:43 +0000 Subject: Implementation of async DNS lookup. Reviewed-by: Shane Kearns --- src/network/kernel/qhostinfo.cpp | 53 ++++- src/network/kernel/qhostinfo_p.h | 115 ++++++++++- src/network/kernel/qhostinfo_symbian.cpp | 323 ++++++++++++++++++++++++++++++- 3 files changed, 473 insertions(+), 18 deletions(-) diff --git a/src/network/kernel/qhostinfo.cpp b/src/network/kernel/qhostinfo.cpp index 5ec6041..7a15a05 100644 --- a/src/network/kernel/qhostinfo.cpp +++ b/src/network/kernel/qhostinfo.cpp @@ -56,10 +56,14 @@ QT_BEGIN_NAMESPACE -Q_GLOBAL_STATIC(QHostInfoLookupManager, theHostInfoLookupManager) - //#define QHOSTINFO_DEBUG +#ifndef Q_OS_SYMBIAN +Q_GLOBAL_STATIC(QHostInfoLookupManager, theHostInfoLookupManager) +#else +Q_GLOBAL_STATIC(QSymbianHostInfoLookupManger, theHostInfoLookupManager) +#endif + /*! \class QHostInfo \brief The QHostInfo class provides static functions for host name lookups. @@ -152,6 +156,7 @@ int QHostInfo::lookupHost(const QString &name, QObject *receiver, qDebug("QHostInfo::lookupHost(\"%s\", %p, %s)", name.toLatin1().constData(), receiver, member ? member + 1 : 0); #endif + if (!QAbstractEventDispatcher::instance(QThread::currentThread())) { qWarning("QHostInfo::lookupHost() called with no event dispatcher"); return -1; @@ -172,7 +177,9 @@ int QHostInfo::lookupHost(const QString &name, QObject *receiver, return id; } +#ifndef Q_OS_SYMBIAN QHostInfoLookupManager *manager = theHostInfoLookupManager(); + if (manager) { // the application is still alive if (manager->cache.isEnabled()) { @@ -187,11 +194,38 @@ int QHostInfo::lookupHost(const QString &name, QObject *receiver, return id; } } + // cache is not enabled or it was not in the cache, do normal lookup QHostInfoRunnable* runnable = new QHostInfoRunnable(name, id); QObject::connect(&runnable->resultEmitter, SIGNAL(resultsReady(QHostInfo)), receiver, member, Qt::QueuedConnection); manager->scheduleLookup(runnable); } +#else + QSymbianHostInfoLookupManger *manager = theHostInfoLookupManager(); + + if (manager) { + // the application is still alive + if (manager->cache.isEnabled()) { + // check cache first + bool valid = false; + QHostInfo info = manager->cache.get(name, &valid); + if (valid) { + info.setLookupId(id); + QHostInfoResult result; + QObject::connect(&result, SIGNAL(resultsReady(QHostInfo)), receiver, member, Qt::QueuedConnection); + result.emitResultsReady(info); + return id; + } + } + + // cache is not enabled or it was not in the cache, do normal lookup + QSymbianHostResolver *symbianResolver = 0; + QT_TRAP_THROWING(symbianResolver = new QSymbianHostResolver(name, id)); + QObject::connect(&symbianResolver->resultEmitter, SIGNAL(resultsReady(QHostInfo)), receiver, member, Qt::QueuedConnection); + manager->scheduleLookup(symbianResolver); + } +#endif + return id; } @@ -225,7 +259,7 @@ QHostInfo QHostInfo::fromName(const QString &name) #endif QHostInfo hostInfo = QHostInfoAgent::fromName(name); - QHostInfoLookupManager *manager = theHostInfoLookupManager(); + QAbstractHostInfoLookupManger* manager = theHostInfoLookupManager(); manager->cache.put(name, hostInfo); return hostInfo; } @@ -406,6 +440,7 @@ void QHostInfo::setErrorString(const QString &str) \sa hostName() */ +#ifndef Q_OS_SYMBIAN QHostInfoRunnable::QHostInfoRunnable(QString hn, int i) : toBeLookedUp(hn), id(i) { setAutoDelete(true); @@ -632,6 +667,7 @@ void QHostInfoLookupManager::lookupFinished(QHostInfoRunnable *r) finishedLookups.append(r); work(); } +#endif // This function returns immediately when we had a result in the cache, else it will later emit a signal QHostInfo qt_qhostinfo_lookup(const QString &name, QObject *receiver, const char *member, bool *valid, int *id) @@ -640,7 +676,7 @@ QHostInfo qt_qhostinfo_lookup(const QString &name, QObject *receiver, const char *id = -1; // check cache - QHostInfoLookupManager* manager = theHostInfoLookupManager(); + QAbstractHostInfoLookupManger* manager = theHostInfoLookupManager(); if (manager && manager->cache.isEnabled()) { QHostInfo info = manager->cache.get(name, valid); if (*valid) { @@ -657,7 +693,7 @@ QHostInfo qt_qhostinfo_lookup(const QString &name, QObject *receiver, const char void qt_qhostinfo_clear_cache() { - QHostInfoLookupManager* manager = theHostInfoLookupManager(); + QAbstractHostInfoLookupManger* manager = theHostInfoLookupManager(); if (manager) { manager->clear(); } @@ -665,7 +701,7 @@ void qt_qhostinfo_clear_cache() void Q_AUTOTEST_EXPORT qt_qhostinfo_enable_cache(bool e) { - QHostInfoLookupManager* manager = theHostInfoLookupManager(); + QAbstractHostInfoLookupManger* manager = theHostInfoLookupManager(); if (manager) { manager->cache.setEnabled(e); } @@ -733,4 +769,9 @@ void QHostInfoCache::clear() cache.clear(); } +QAbstractHostInfoLookupManger* QAbstractHostInfoLookupManger::globalInstance() +{ + return theHostInfoLookupManager(); +} + QT_END_NAMESPACE diff --git a/src/network/kernel/qhostinfo_p.h b/src/network/kernel/qhostinfo_p.h index b568ec2..ec7a63e 100644 --- a/src/network/kernel/qhostinfo_p.h +++ b/src/network/kernel/qhostinfo_p.h @@ -69,9 +69,18 @@ #include #include +#include + +#ifdef Q_OS_SYMBIAN +// Symbian Headers +#include +#include +#endif + QT_BEGIN_NAMESPACE + class QHostInfoResult : public QObject { Q_OBJECT @@ -91,6 +100,12 @@ class QHostInfoAgent : public QObject Q_OBJECT public: static QHostInfo fromName(const QString &hostName); + static QHostInfo fromName(const QString &hostName, QSharedPointer networkSession); + +#ifdef Q_OS_SYMBIAN + static int lookupHost(const QString &name, QObject *receiver, const char *member); + static void abortHostLookup(int lookupId); +#endif }; class QHostInfoPrivate @@ -151,7 +166,25 @@ public: QHostInfoResult resultEmitter; }; -class QHostInfoLookupManager : public QObject + +class QAbstractHostInfoLookupManger : public QObject +{ + Q_OBJECT + +public: + ~QAbstractHostInfoLookupManger() {} + virtual void clear() = 0; + + QHostInfoCache cache; + +protected: + QAbstractHostInfoLookupManger() {} + static QAbstractHostInfoLookupManger* globalInstance(); + +}; + +#ifndef Q_OS_SYMBIAN +class QHostInfoLookupManager : public QAbstractInfoLookupManager { Q_OBJECT public: @@ -169,8 +202,6 @@ public: void lookupFinished(QHostInfoRunnable *r); bool wasAborted(int id); - QHostInfoCache cache; - friend class QHostInfoRunnable; protected: QList currentLookups; // in progress @@ -189,6 +220,84 @@ private slots: void waitForThreadPoolDone() { threadPool.waitForDone(); } }; +#else + +class QSymbianHostResolver : public CActive +{ +public: + QSymbianHostResolver(const QString &hostName, int id); + ~QSymbianHostResolver(); + + QHostInfo requestHostLookup(); + int id(); + + QHostInfoResult resultEmitter; + +private: + void DoCancel(); + void RunL(); + void run(); + TInt RunError(TInt aError); + + void processNameResults(); + void processAddressResults(); + +private: + int iId; + + const QString iHostName; + + RSocketServ& iSocketServ; + RHostResolver iHostResolver; + + TRequestStatus iStatus; + + TNameEntry iNameResult; + QHostAddress iAddress; + + QHostInfo iResults; + + enum { + EIdle, + EGetByName, + EGetByAddress + } iState; +}; + +class QSymbianHostInfoLookupManger : public QAbstractHostInfoLookupManger +{ + Q_OBJECT +public: + QSymbianHostInfoLookupManger(); + ~QSymbianHostInfoLookupManger(); + + static QSymbianHostInfoLookupManger* globalInstance(); + + int id(); + void clear(); + + // called from QHostInfo + void scheduleLookup(QSymbianHostResolver *r); + void abortLookup(int id); + + // called from QSymbianHostResolver + void lookupFinished(QSymbianHostResolver *r); + +private: + void runNextLookup(); + + static const int KMaxConcurrentLookups = 5; + + RPointerArray iCurrentLookups; + RPointerArray iScheduledLookups; + RPointerArray iFinishedLookups; + + QMutex mutex; +}; +#endif + + + QT_END_NAMESPACE #endif // QHOSTINFO_P_H diff --git a/src/network/kernel/qhostinfo_symbian.cpp b/src/network/kernel/qhostinfo_symbian.cpp index 9599274..2b582bd 100644 --- a/src/network/kernel/qhostinfo_symbian.cpp +++ b/src/network/kernel/qhostinfo_symbian.cpp @@ -41,10 +41,6 @@ //#define QHOSTINFO_DEBUG -// Symbian Headers -#include -#include - // Qt Headers #include #include @@ -54,11 +50,13 @@ #include "qhostinfo_p.h" #include +#include QT_BEGIN_NAMESPACE -QHostInfo QHostInfoAgent::fromName(const QString &hostName) + +QHostInfo QHostInfoAgent::fromName(const QString &hostName, QSharedPointer networkSession) { QHostInfo results; @@ -66,12 +64,20 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) RSocketServ socketServ(qt_symbianGetSocketServer()); RHostResolver hostResolver; + + // TODO - check if networkSession is null + // RConnection connection = magicalApi(networkSession); + // int err = connection.Open(blah, blah); + // if (err) { + // do something; + // } + // Will return both IPv4 and IPv6 // TODO: Pass RHostResolver.Open() the global RConnection int err = hostResolver.Open(socketServ, KAfInet, KProtocolInetUdp); if (err) { results.setError(QHostInfo::UnknownError); - results.setErrorString(tr("Symbian error code: %1").arg(err)); + results.setErrorString(QSystemError(err,QSystemError::NativeError).toString()); return results; } @@ -99,7 +105,7 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) results.setErrorString(tr("Host not found")); } else { results.setError(QHostInfo::UnknownError); - results.setErrorString(tr("Symbian error code: %1").arg(err)); + results.setErrorString(QSystemError(err,QSystemError::NativeError).toString()); } return results; @@ -134,7 +140,7 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) results.setErrorString(tr("Host not found")); } else { results.setError(QHostInfo::UnknownError); - results.setErrorString(tr("Symbian error code: %1").arg(err)); + results.setErrorString(QSystemError(err,QSystemError::NativeError).toString()); } return results; @@ -156,7 +162,8 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) hostAdd = nameResult().iAddr; hostAdd.Output(ipAddr); - if (ipAddr.Length() > 0) { + // Ensure that record is valid (not an alias and with length greater than 0) + if (!(nameResult().iFlags & TNameRecord::EAlias) && (ipAddr.Length() > 0)) { if (nameResult().iAddr.Family() == KAfInet) { // IPv4 - prepend hostAddresses.prepend(QHostAddress(qt_TDesC2QString(ipAddr))); @@ -173,6 +180,13 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) return results; } +QHostInfo QHostInfoAgent::fromName(const QString &hostName) +{ + // null shared pointer + QSharedPointer networkSession; + return fromName(hostName, networkSession); +} + QString QHostInfo::localHostName() { // Connect to ESOCK @@ -201,4 +215,295 @@ QString QHostInfo::localDomainName() return QString(); } + +QSymbianHostResolver::QSymbianHostResolver(const QString &hostName, int identifier) + : CActive(CActive::EPriorityStandard), iId(identifier), iHostName(hostName), + iSocketServ(qt_symbianGetSocketServer()) +{ + CActiveScheduler::Add(this); +} + +QSymbianHostResolver::~QSymbianHostResolver() +{ + Cancel(); + iHostResolver.Close(); +} + +// Async equivalent to QHostInfoAgent::fromName() +QHostInfo QSymbianHostResolver::requestHostLookup() +{ + +#if defined(QHOSTINFO_DEBUG) + qDebug("QHostInfoAgent::fromName(%s) looking up...", + hostName.toLatin1().constData()); +#endif + + int err = iHostResolver.Open(iSocketServ, KAfInet, KProtocolInetUdp); + if (err) { + // What are we doing with iResults?? + iResults.setError(QHostInfo::UnknownError); + iResults.setErrorString(QObject::tr("Symbian error code: %1").arg(err)); + + iHostResolver.Close(); + return iResults; + } + + if (iAddress.setAddress(iHostName)) { + // Reverse lookup + + TInetAddr IpAdd; + IpAdd.Input(qt_QString2TPtrC(iHostName)); + + // Asynchronous request. + iHostResolver.GetByAddress(IpAdd, iNameResult, iStatus); // <---- ASYNC + iState = EGetByAddress; + + } else { + + // IDN support + QByteArray aceHostname = QUrl::toAce(iHostName); + iResults.setHostName(iHostName); + if (aceHostname.isEmpty()) { + iResults.setError(QHostInfo::HostNotFound); + iResults.setErrorString(iHostName.isEmpty() ? + QCoreApplication::translate("QHostInfoAgent", "No host name given") : + QCoreApplication::translate("QHostInfoAgent", "Invalid hostname")); + + iHostResolver.Close(); + return iResults; + } + + // Asynchronous request. + iHostResolver.GetByName(qt_QString2TPtrC(QString::fromLatin1(aceHostname)), iNameResult, iStatus); + iState = EGetByName; + } + + SetActive(); + + return iResults; +} + +void QSymbianHostResolver::DoCancel() +{ + QSymbianHostInfoLookupManger *manager = QSymbianHostInfoLookupManger::globalInstance(); + manager->lookupFinished(this); + iHostResolver.Cancel(); +} + +void QSymbianHostResolver::RunL() +{ + QT_TRYCATCH_LEAVING(run()); +} + +void QSymbianHostResolver::run() +{ + if (iState == EGetByName) + processNameResults(); + else if (iState == EGetByAddress) + processAddressResults(); + + iState = EIdle; + + QSymbianHostInfoLookupManger *manager = QSymbianHostInfoLookupManger::globalInstance(); + manager->lookupFinished(this); + + resultEmitter.emitResultsReady(iResults); + + delete this; +} + +TInt QSymbianHostResolver::RunError(TInt aError) +{ + QT_TRY { + iState = EIdle; + + QSymbianHostInfoLookupManger *manager = QSymbianHostInfoLookupManger::globalInstance(); + manager->lookupFinished(this); + + iResults.setError(QHostInfo::UnknownError); + iResults.setErrorString(QSystemError(aError,QSystemError::NativeError).toString()); + + resultEmitter.emitResultsReady(iResults); + } + QT_CATCH(...) {} + + delete this; + + return KErrNone; +} + +void QSymbianHostResolver::processNameResults() +{ + TInt err = iStatus.Int(); + if (err < 0) { + // TODO - Could there be other errors? Symbian docs don't say. + if (err = KErrNotFound) { + iResults.setError(QHostInfo::HostNotFound); + iResults.setErrorString(QObject::tr("Host not found")); + } else { + iResults.setError(QHostInfo::UnknownError); + iResults.setErrorString(QSystemError(err,QSystemError::NativeError).toString()); + } + + iHostResolver.Close(); + return; + } + + QList hostAddresses; + + TInetAddr hostAdd = iNameResult().iAddr; + // 39 is the maximum length of an IPv6 address. + TBuf<39> ipAddr; + + // Fill ipAddr with the IP address from hostAdd + hostAdd.Output(ipAddr); + if (ipAddr.Length() > 0) + hostAddresses.append(QHostAddress(qt_TDesC2QString(ipAddr))); + + // Check if there's more than one IP address linkd to this name + while (iHostResolver.Next(iNameResult) == KErrNone) { + hostAdd = iNameResult().iAddr; + hostAdd.Output(ipAddr); + + // Ensure that record is valid (not an alias and with length greater than 0) + if (!(iNameResult().iFlags & TNameRecord::EAlias) && (ipAddr.Length() > 0)) { + if (iNameResult().iAddr.Family() == KAfInet) { + // IPv4 - prepend + hostAddresses.prepend(QHostAddress(qt_TDesC2QString(ipAddr))); + } else { + // IPv6 - append + hostAddresses.append(QHostAddress(qt_TDesC2QString(ipAddr))); + } + } + } + + iResults.setAddresses(hostAddresses); +} + +void QSymbianHostResolver::processAddressResults() +{ + TInt err = iStatus.Int(); + + if (err < 0) { + // TODO - Could there be other errors? Symbian docs don't say. + if (err = KErrNotFound) { + iResults.setError(QHostInfo::HostNotFound); + iResults.setErrorString(QObject::tr("Host not found")); + } else { + iResults.setError(QHostInfo::UnknownError); + iResults.setErrorString(QSystemError(err,QSystemError::NativeError).toString()); + } + + return; + } + + iResults.setHostName(qt_TDesC2QString(iNameResult().iName)); + iResults.setAddresses(QList() << iAddress); +} + + +int QSymbianHostResolver::id() +{ + return iId; +} + +QSymbianHostInfoLookupManger::QSymbianHostInfoLookupManger() +{ +} + +QSymbianHostInfoLookupManger::~QSymbianHostInfoLookupManger() +{ + iCurrentLookups.Close(); + iScheduledLookups.Close(); +} + +void QSymbianHostInfoLookupManger::clear() +{ + QMutexLocker locker(&mutex); + iCurrentLookups.ResetAndDestroy(); + iScheduledLookups.ResetAndDestroy(); +} + +void QSymbianHostInfoLookupManger::lookupFinished(QSymbianHostResolver *r) +{ + QMutexLocker locker(&mutex); + + // remove finished lookup from array and destroy + TInt count = iCurrentLookups.Count(); + for (TInt i = 0; i < count; i++) { + if (iCurrentLookups[i]->id() == r->id()) { + iCurrentLookups.Remove(i); + break; + } + } + + runNextLookup(); +} + +void QSymbianHostInfoLookupManger::runNextLookup() +{ + // check to see if there are any scheduled lookups + if (iScheduledLookups.Count() > 0) { + // if so, move one to the current lookups and run it + // FIFO + QSymbianHostResolver* hostResolver = iScheduledLookups[0]; + iCurrentLookups.Append(hostResolver); + iScheduledLookups.Remove(0); + hostResolver->requestHostLookup(); + } +} + +// called from QHostInfo +void QSymbianHostInfoLookupManger::scheduleLookup(QSymbianHostResolver* r) +{ + QMutexLocker locker(&mutex); + + // Check to see if we have space on the current lookups pool. + if (iCurrentLookups.Count() >= KMaxConcurrentLookups) { + // If no, schedule for later. + iScheduledLookups.Append(r); + return; + } else { + // If yes, add it to the current lookups. + iCurrentLookups.Append(r); + + // ... and trigger the async call. + r->requestHostLookup(); + } +} + +void QSymbianHostInfoLookupManger::abortLookup(int id) +{ + QMutexLocker locker(&mutex); + + int i = 0; + // Find the aborted lookup by ID. + // First in the current lookups. + for (i = 0; i < iCurrentLookups.Count(); i++) { + if (id = iCurrentLookups[i]->id()) { + QSymbianHostResolver* r = iCurrentLookups[i]; + iCurrentLookups.Remove(i); + r->Cancel(); + runNextLookup(); + return; + } + } + // Then in the scheduled lookups. + for (i = 0; i < iScheduledLookups.Count(); i++) { + if (id = iScheduledLookups[i]->id()) { + QSymbianHostResolver* r = iScheduledLookups[i]; + iScheduledLookups.Remove(i); + delete r; + return; + } + } +} + + +QSymbianHostInfoLookupManger* QSymbianHostInfoLookupManger::globalInstance() +{ + return static_cast + (QAbstractHostInfoLookupManger::globalInstance()); +} + QT_END_NAMESPACE -- cgit v0.12 From 13f415e7d54ef8e2aaccabfb04f29ccfde0520df Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Wed, 16 Mar 2011 18:50:02 +0000 Subject: Make tst_QEventLoop::processEventsExcludeSocket stricter The test was only checking that the socket event is not processed when excluded. I have added an additional test that a further call with socket events included results in the deferred socket event being processed. i.e. makes sure events are deferred to later and not lost. Also fixed capabilities of the autotest, so this test case can run. Reviewed-by: Markus Goetz --- tests/auto/qeventloop/qeventloop.pro | 1 + tests/auto/qeventloop/tst_qeventloop.cpp | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/tests/auto/qeventloop/qeventloop.pro b/tests/auto/qeventloop/qeventloop.pro index f6c24ae..e7489fa 100644 --- a/tests/auto/qeventloop/qeventloop.pro +++ b/tests/auto/qeventloop/qeventloop.pro @@ -5,3 +5,4 @@ QT += network win32:!wince*:LIBS += -luser32 +symbian:TARGET.CAPABILITY += NetworkServices \ No newline at end of file diff --git a/tests/auto/qeventloop/tst_qeventloop.cpp b/tests/auto/qeventloop/tst_qeventloop.cpp index 6860f19..aad8390 100644 --- a/tests/auto/qeventloop/tst_qeventloop.cpp +++ b/tests/auto/qeventloop/tst_qeventloop.cpp @@ -604,6 +604,7 @@ public slots: serverSocket->flush(); QCoreApplication::processEvents(QEventLoop::ExcludeSocketNotifiers); testResult = dataArrived; + QCoreApplication::processEvents(); //check the deferred event is processed serverSocket->close(); QThread::currentThread()->exit(0); } @@ -620,9 +621,11 @@ public: if (tester->init()) exec(); testResult = tester->testResult; + dataArrived = tester->dataArrived; delete tester; } bool testResult; + bool dataArrived; }; void tst_QEventLoop::processEventsExcludeSocket() @@ -631,6 +634,7 @@ void tst_QEventLoop::processEventsExcludeSocket() thread.start(); QVERIFY(thread.wait()); QVERIFY(!thread.testResult); + QVERIFY(thread.dataArrived); } class TimerReceiver : public QObject -- cgit v0.12 From 1adef92e1b1ba9872c9676efd701eb0fd0a3a907 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Wed, 16 Mar 2011 18:59:45 +0000 Subject: Implement QEventLoop::ExcludeSocketNotifiers for symbian socket engine As the symbian socket engine is driven by an active object in the QtNetwork dll, this needs to hook into the event dispatcher in the QtCore dll. The QActiveObject base class is now a private export from QtCore The method of deferring socket events now works with any kind of QActiveObject, and not only the QSocketActiveObject (which handles "open C" sockets) The base class has a new function, to check if socket events are blocked. If so, it adds the active object to the deferred queue. The derived class should return from it's RunL in this case, which will be called again later. (same usage as the maybeQueueForLater function) reactivateAndComplete function in the event dispatcher is changed to complete the active object again with the same status code as originally. Previously it always used KErrNone, which is not ok for QAsyncSelect as it needs to check the error code from the asynchronous call. Reviewed-by: Markus Goetz Reviewed-by: mread --- src/corelib/kernel/qeventdispatcher_symbian.cpp | 79 +++++++++++++++---------- src/corelib/kernel/qeventdispatcher_symbian_p.h | 13 ++-- src/network/socket/qsymbiansocketengine.cpp | 28 +++++---- src/network/socket/qsymbiansocketengine_p.h | 4 +- 4 files changed, 77 insertions(+), 47 deletions(-) diff --git a/src/corelib/kernel/qeventdispatcher_symbian.cpp b/src/corelib/kernel/qeventdispatcher_symbian.cpp index b074ab4..a95e7d5 100644 --- a/src/corelib/kernel/qeventdispatcher_symbian.cpp +++ b/src/corelib/kernel/qeventdispatcher_symbian.cpp @@ -134,7 +134,7 @@ private: * The QCompleteDeferredAOs class is a special object that runs after all others, which will * reactivate the objects that were previously not run. */ -inline QActiveObject::QActiveObject(TInt priority, QEventDispatcherSymbian *dispatcher) +QActiveObject::QActiveObject(TInt priority, QEventDispatcherSymbian *dispatcher) : CActive(priority), m_dispatcher(dispatcher), m_hasAlreadyRun(false), @@ -166,12 +166,25 @@ bool QActiveObject::maybeQueueForLater() } } +bool QActiveObject::maybeDeferSocketEvent() +{ + Q_ASSERT(!m_hasRunAgain); + Q_ASSERT(m_dispatcher); + if (!m_dispatcher->areSocketEventsBlocked()) { + return false; + } + m_hasRunAgain = true; + m_dispatcher->addDeferredSocketActiveObject(this); + return true; +} + void QActiveObject::reactivateAndComplete() { + TInt error = iStatus.Int(); iStatus = KRequestPending; SetActive(); TRequestStatus *status = &iStatus; - QEventDispatcherSymbian::RequestComplete(status, KErrNone); + QEventDispatcherSymbian::RequestComplete(status, error); m_hasRunAgain = false; m_hasAlreadyRun = false; @@ -634,10 +647,28 @@ void QSocketActiveObject::DoCancel() void QSocketActiveObject::RunL() { + if (maybeDeferSocketEvent()) + return; if (maybeQueueForLater()) return; - QT_TRYCATCH_LEAVING(m_dispatcher->socketFired(this)); + QT_TRYCATCH_LEAVING(run()); +} + +void QSocketActiveObject::run() +{ + QEvent e(QEvent::SockAct); + m_inSocketEvent = true; + QCoreApplication::sendEvent(m_notifier, &e); + m_inSocketEvent = false; + + if (m_deleteLater) { + delete this; + } else { + iStatus = KRequestPending; + SetActive(); + m_dispatcher->reactivateSocketNotifier(m_notifier); + } } void QSocketActiveObject::deleteLater() @@ -912,27 +943,6 @@ void QEventDispatcherSymbian::timerFired(int timerId) return; } -void QEventDispatcherSymbian::socketFired(QSocketActiveObject *socketAO) -{ - if (m_noSocketEvents) { - m_deferredSocketEvents.append(socketAO); - return; - } - - QEvent e(QEvent::SockAct); - socketAO->m_inSocketEvent = true; - QCoreApplication::sendEvent(socketAO->m_notifier, &e); - socketAO->m_inSocketEvent = false; - - if (socketAO->m_deleteLater) { - delete socketAO; - } else { - socketAO->iStatus = KRequestPending; - socketAO->SetActive(); - reactivateSocketNotifier(socketAO->m_notifier); - } -} - void QEventDispatcherSymbian::wakeUpWasCalled() { // The reactivation should happen in RunL, right before the call to this function. @@ -993,6 +1003,12 @@ inline void QEventDispatcherSymbian::addDeferredActiveObject(QActiveObject *obje inline void QEventDispatcherSymbian::removeDeferredActiveObject(QActiveObject *object) { m_deferredActiveObjects.removeAll(object); + m_deferredSocketEvents.removeAll(object); +} + +inline void QEventDispatcherSymbian::addDeferredSocketActiveObject(QActiveObject *object) +{ + m_deferredSocketEvents.append(object); } void QEventDispatcherSymbian::queueDeferredActiveObjectsCompletion() @@ -1018,7 +1034,8 @@ bool QEventDispatcherSymbian::sendDeferredSocketEvents() bool sentAnyEvents = false; while (!m_deferredSocketEvents.isEmpty()) { sentAnyEvents = true; - socketFired(m_deferredSocketEvents.takeFirst()); + QActiveObject *object = m_deferredSocketEvents.takeFirst(); + object->reactivateAndComplete(); } return sentAnyEvents; @@ -1037,17 +1054,18 @@ bool QEventDispatcherSymbian::hasPendingEvents() void QEventDispatcherSymbian::registerSocketNotifier ( QSocketNotifier * notifier ) { - //TODO: just need to be able to do something when event loop has sockets disabled -/* QSocketActiveObject *socketAO = new QSocketActiveObject(this, notifier); + //note - this is only for "open C" file descriptors + //for native sockets, an active object in the symbian socket engine handles this + QSocketActiveObject *socketAO = new QSocketActiveObject(this, notifier); Q_CHECK_PTR(socketAO); m_notifiers.insert(notifier, socketAO); - selectThread().requestSocketEvents(notifier, &socketAO->iStatus);*/ + selectThread().requestSocketEvents(notifier, &socketAO->iStatus); } void QEventDispatcherSymbian::unregisterSocketNotifier ( QSocketNotifier * notifier ) { - //TODO: just need to be able to do something when event loop has sockets disabled - /* + //note - this is only for "open C" file descriptors + //for native sockets, an active object in the symbian socket engine handles this if (m_selectThread) m_selectThread->cancelSocketEvents(notifier); if (m_notifiers.contains(notifier)) { @@ -1056,7 +1074,6 @@ void QEventDispatcherSymbian::unregisterSocketNotifier ( QSocketNotifier * notif sockObj->deleteLater(); m_notifiers.remove(notifier); } - */ } void QEventDispatcherSymbian::reactivateSocketNotifier(QSocketNotifier *notifier) diff --git a/src/corelib/kernel/qeventdispatcher_symbian_p.h b/src/corelib/kernel/qeventdispatcher_symbian_p.h index bf28144..e07d475 100644 --- a/src/corelib/kernel/qeventdispatcher_symbian_p.h +++ b/src/corelib/kernel/qeventdispatcher_symbian_p.h @@ -77,13 +77,14 @@ QT_BEGIN_NAMESPACE class QEventDispatcherSymbian; class QTimerActiveObject; -class Q_AUTOTEST_EXPORT QActiveObject : public CActive +class Q_CORE_EXPORT QActiveObject : public CActive { public: QActiveObject(TInt priority, QEventDispatcherSymbian *dispatcher); ~QActiveObject(); bool maybeQueueForLater(); + bool maybeDeferSocketEvent(); void reactivateAndComplete(); @@ -176,6 +177,7 @@ public: protected: void DoCancel(); void RunL(); + void run(); private: QSocketNotifier *m_notifier; @@ -244,7 +246,6 @@ public: void closingDown(); void timerFired(int timerId); - void socketFired(QSocketActiveObject *socketAO); void wakeUpWasCalled(); void reactivateSocketNotifier(QSocketNotifier *notifier); @@ -256,6 +257,9 @@ public: inline int iterationCount() const { return m_iterationCount; } + void addDeferredSocketActiveObject(QActiveObject *object); + inline bool areSocketEventsBlocked() const { return m_noSocketEvents; } + static void RequestComplete(TRequestStatus *&status, TInt reason); static void RequestComplete(RThread &threadHandle, TRequestStatus *&status, TInt reason); @@ -281,8 +285,9 @@ private: unsigned char m_iterationCount; bool m_insideTimerEvent; bool m_noSocketEvents; - QList m_deferredSocketEvents; - + //deferred until socket events are enabled + QList m_deferredSocketEvents; + //deferred until idle QList m_deferredActiveObjects; int m_delay; diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index 688f724..07b2e5a 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -63,6 +63,7 @@ #include #include +#include #include #include @@ -187,7 +188,6 @@ bool QSymbianSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType so TUint protocol = (socketType == QAbstractSocket::UdpSocket) ? KProtocolInetUdp : KProtocolInetTcp; //Check if there is a user specified session - RConnection *connection = 0; QVariant v(q->property("_q_networksession")); TInt err; if (v.isValid()) { @@ -1437,7 +1437,9 @@ void QSymbianSocketEngine::setReadNotificationEnabled(bool enable) #endif d->readNotificationsEnabled = enable; if (enable && d->threadData->eventDispatcher && !d->asyncSelect) - d->asyncSelect = q_check_ptr(new QAsyncSelect(0, d->nativeSocket, this)); + d->asyncSelect = q_check_ptr( + new QAsyncSelect(static_cast(d->threadData->eventDispatcher), + d->nativeSocket, this)); // TODO: what do we do if event dispatcher doesn't exist yet? if (d->asyncSelect) d->asyncSelect->IssueRequest(); @@ -1459,7 +1461,9 @@ void QSymbianSocketEngine::setWriteNotificationEnabled(bool enable) #endif d->writeNotificationsEnabled = enable; if (enable && d->threadData->eventDispatcher && !d->asyncSelect) - d->asyncSelect = q_check_ptr(new QAsyncSelect(0, d->nativeSocket, this)); + d->asyncSelect = q_check_ptr( + new QAsyncSelect(static_cast(d->threadData->eventDispatcher), + d->nativeSocket, this)); // TODO: what do we do if event dispatcher doesn't exist yet? if (d->asyncSelect) d->asyncSelect->IssueRequest(); @@ -1483,7 +1487,9 @@ void QSymbianSocketEngine::setExceptionNotificationEnabled(bool enable) #endif d->exceptNotificationsEnabled = enable; if (enable && d->threadData->eventDispatcher && !d->asyncSelect) - d->asyncSelect = q_check_ptr(new QAsyncSelect(0, d->nativeSocket, this)); + d->asyncSelect = q_check_ptr( + new QAsyncSelect(static_cast(d->threadData->eventDispatcher), + d->nativeSocket, this)); if (d->asyncSelect) d->asyncSelect->IssueRequest(); } @@ -1597,15 +1603,17 @@ bool QSymbianSocketEngine::event(QEvent* ev) qDebug() << "PostThreadChangeEvent" << d->readNotificationsEnabled << d->writeNotificationsEnabled << d->exceptNotificationsEnabled; #endif // recreate select in new thread - d->asyncSelect = q_check_ptr(new QAsyncSelect(0, d->nativeSocket, this)); + d->asyncSelect = q_check_ptr( + new QAsyncSelect(static_cast(d->threadData->eventDispatcher), + d->nativeSocket, this)); d->asyncSelect->IssueRequest(); return true; } return QAbstractSocketEngine::event(ev); } -QAsyncSelect::QAsyncSelect(QAbstractEventDispatcher *dispatcher, RSocket& sock, QSymbianSocketEngine *parent) - : CActive(CActive::EPriorityStandard), +QAsyncSelect::QAsyncSelect(QEventDispatcherSymbian *dispatcher, RSocket& sock, QSymbianSocketEngine *parent) + : QActiveObject(CActive::EPriorityStandard, dispatcher), m_inSocketEvent(false), m_deleteLater(false), m_socket(sock), @@ -1652,9 +1660,9 @@ TInt QAsyncSelect::RunError(TInt aError) void QAsyncSelect::run() { - //TODO: block when event loop demands it - //if (maybeQueueForLater()) - // return; + //when event loop disabled socket events, defer until later + if (maybeDeferSocketEvent()) + return; m_inSocketEvent = true; m_selectBuf() &= m_selectFlags; //the select ioctl reports everything, so mask to only what we requested //KSockSelectReadContinuation is for reading datagrams in a mode that doesn't discard when the diff --git a/src/network/socket/qsymbiansocketengine_p.h b/src/network/socket/qsymbiansocketengine_p.h index 432e4dc..bbe1269 100644 --- a/src/network/socket/qsymbiansocketengine_p.h +++ b/src/network/socket/qsymbiansocketengine_p.h @@ -151,10 +151,10 @@ class QSocketNotifier; class QReadNotifier; class QWriteNotifier; class QExceptionNotifier; -class QAsyncSelect : public CActive +class QAsyncSelect : public QActiveObject { public: - QAsyncSelect(QAbstractEventDispatcher *dispatcher, RSocket& sock, QSymbianSocketEngine *parent); + QAsyncSelect(QEventDispatcherSymbian *dispatcher, RSocket& sock, QSymbianSocketEngine *parent); ~QAsyncSelect(); void deleteLater(); -- cgit v0.12 From 2e2c3aab63b066aa2321792e6adeab76d12c77d1 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Thu, 17 Mar 2011 14:55:20 +0000 Subject: tst_qudpsocket - fix capabilities Reviewed-by: Trust Me --- tests/auto/qudpsocket/clientserver/clientserver.pro | 2 +- tests/auto/qudpsocket/qudpsocket.pro | 2 -- tests/auto/qudpsocket/test/test.pro | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/auto/qudpsocket/clientserver/clientserver.pro b/tests/auto/qudpsocket/clientserver/clientserver.pro index 5fe65b3..6da1486 100644 --- a/tests/auto/qudpsocket/clientserver/clientserver.pro +++ b/tests/auto/qudpsocket/clientserver/clientserver.pro @@ -5,4 +5,4 @@ CONFIG -= app_bundle TARGET = clientserver DESTDIR = ./ - +symbian: TARGET.CAPABILITY += NetworkServices diff --git a/tests/auto/qudpsocket/qudpsocket.pro b/tests/auto/qudpsocket/qudpsocket.pro index 8fd3545..4ddb717 100644 --- a/tests/auto/qudpsocket/qudpsocket.pro +++ b/tests/auto/qudpsocket/qudpsocket.pro @@ -1,6 +1,4 @@ TEMPLATE = subdirs SUBDIRS = test clientserver -symbian: TARGET.CAPABILITY = NetworkServices - diff --git a/tests/auto/qudpsocket/test/test.pro b/tests/auto/qudpsocket/test/test.pro index 7e5ffe4..b68d30c 100644 --- a/tests/auto/qudpsocket/test/test.pro +++ b/tests/auto/qudpsocket/test/test.pro @@ -22,4 +22,4 @@ wince*|symbian: { TARGET = tst_qudpsocket - +symbian: TARGET.CAPABILITY += NetworkServices -- cgit v0.12 From 690ca356c52f0e4f83f5b6cb4b54fdc6db2af5ba Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Thu, 17 Mar 2011 16:12:08 +0100 Subject: QHostInfo: Compile fix for non-Symbian --- src/network/kernel/qhostinfo_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/kernel/qhostinfo_p.h b/src/network/kernel/qhostinfo_p.h index ec7a63e..72175f0 100644 --- a/src/network/kernel/qhostinfo_p.h +++ b/src/network/kernel/qhostinfo_p.h @@ -184,7 +184,7 @@ protected: }; #ifndef Q_OS_SYMBIAN -class QHostInfoLookupManager : public QAbstractInfoLookupManager +class QHostInfoLookupManager : public QAbstractHostInfoLookupManger { Q_OBJECT public: -- cgit v0.12 From b35009bab4d4353aa82830f4f7f8c29700b2bd08 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 18 Mar 2011 11:21:08 +0000 Subject: Fix "wrong lookup id" warning from QAbstractSocket Symbian host info implementation was using default constructor for the results, which sets the id to -1, and storing the id seperately. Changed this to use the constructor that specifies the id, and use the id inside the results instead of storing it separately (just a change to the accessor function) Reviewed-by: Markus Goetz --- src/network/kernel/qhostinfo_p.h | 2 -- src/network/kernel/qhostinfo_symbian.cpp | 28 +++++++++++++++++++++++----- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/network/kernel/qhostinfo_p.h b/src/network/kernel/qhostinfo_p.h index 72175f0..79fad84 100644 --- a/src/network/kernel/qhostinfo_p.h +++ b/src/network/kernel/qhostinfo_p.h @@ -243,8 +243,6 @@ private: void processAddressResults(); private: - int iId; - const QString iHostName; RSocketServ& iSocketServ; diff --git a/src/network/kernel/qhostinfo_symbian.cpp b/src/network/kernel/qhostinfo_symbian.cpp index 2b582bd..ad5f38a 100644 --- a/src/network/kernel/qhostinfo_symbian.cpp +++ b/src/network/kernel/qhostinfo_symbian.cpp @@ -217,14 +217,17 @@ QString QHostInfo::localDomainName() QSymbianHostResolver::QSymbianHostResolver(const QString &hostName, int identifier) - : CActive(CActive::EPriorityStandard), iId(identifier), iHostName(hostName), - iSocketServ(qt_symbianGetSocketServer()) + : CActive(CActive::EPriorityStandard), iHostName(hostName), + iSocketServ(qt_symbianGetSocketServer()), iResults(identifier) { CActiveScheduler::Add(this); } QSymbianHostResolver::~QSymbianHostResolver() { +#if defined(QHOSTINFO_DEBUG) + qDebug() << "QSymbianHostInfoLookupManger::~QSymbianHostResolver" << id(); +#endif Cancel(); iHostResolver.Close(); } @@ -234,8 +237,8 @@ QHostInfo QSymbianHostResolver::requestHostLookup() { #if defined(QHOSTINFO_DEBUG) - qDebug("QHostInfoAgent::fromName(%s) looking up...", - hostName.toLatin1().constData()); + qDebug("QSymbianHostResolver::requestHostLookup(%s) looking up... (id = %d)", + iHostName.toLatin1().constData(), id()); #endif int err = iHostResolver.Open(iSocketServ, KAfInet, KProtocolInetUdp); @@ -404,7 +407,7 @@ void QSymbianHostResolver::processAddressResults() int QSymbianHostResolver::id() { - return iId; + return iResults.lookupId(); } QSymbianHostInfoLookupManger::QSymbianHostInfoLookupManger() @@ -428,6 +431,9 @@ void QSymbianHostInfoLookupManger::lookupFinished(QSymbianHostResolver *r) { QMutexLocker locker(&mutex); +#if defined(QHOSTINFO_DEBUG) + qDebug() << "QSymbianHostInfoLookupManger::lookupFinished" << r->id() << "current" << iCurrentLookups.Count() << "queued" << iScheduledLookups.Count(); +#endif // remove finished lookup from array and destroy TInt count = iCurrentLookups.Count(); for (TInt i = 0; i < count; i++) { @@ -442,6 +448,9 @@ void QSymbianHostInfoLookupManger::lookupFinished(QSymbianHostResolver *r) void QSymbianHostInfoLookupManger::runNextLookup() { +#if defined(QHOSTINFO_DEBUG) + qDebug() << "QSymbianHostInfoLookupManger::runNextLookup" << "current" << iCurrentLookups.Count() << "queued" << iScheduledLookups.Count(); +#endif // check to see if there are any scheduled lookups if (iScheduledLookups.Count() > 0) { // if so, move one to the current lookups and run it @@ -458,10 +467,16 @@ void QSymbianHostInfoLookupManger::scheduleLookup(QSymbianHostResolver* r) { QMutexLocker locker(&mutex); +#if defined(QHOSTINFO_DEBUG) + qDebug() << "QSymbianHostInfoLookupManger::scheduleLookup" << r->id() << "current" << iCurrentLookups.Count() << "queued" << iScheduledLookups.Count(); +#endif // Check to see if we have space on the current lookups pool. if (iCurrentLookups.Count() >= KMaxConcurrentLookups) { // If no, schedule for later. iScheduledLookups.Append(r); +#if defined(QHOSTINFO_DEBUG) + qDebug(" - scheduled"); +#endif return; } else { // If yes, add it to the current lookups. @@ -476,6 +491,9 @@ void QSymbianHostInfoLookupManger::abortLookup(int id) { QMutexLocker locker(&mutex); +#if defined(QHOSTINFO_DEBUG) + qDebug() << "QSymbianHostInfoLookupManger::abortLookup" << id << "current" << iCurrentLookups.Count() << "queued" << iScheduledLookups.Count(); +#endif int i = 0; // Find the aborted lookup by ID. // First in the current lookups. -- cgit v0.12 From 0679abb6b4f85878cb64fce2089ba926e3b9400c Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 18 Mar 2011 11:30:35 +0000 Subject: handle errors in QSymbianHostResolver::requestHostLookup It was hanging because although the error flags were set, the callback was not emitted and nothing was done with the return value from the function. Now, it sets the state to error, and self completes - so that the completion through RunL is used as normal. Because the state is error, the processing of name/address is skipped and the error string is not rewritten. Note, error being detected at this point is only common when using an explicit network session (as RHostResolver::Open can fail if the RConnection is in the wrong state) Reviewed-by: Markus Goetz --- src/network/kernel/qhostinfo_p.h | 5 ++- src/network/kernel/qhostinfo_symbian.cpp | 64 +++++++++++++++++--------------- 2 files changed, 38 insertions(+), 31 deletions(-) diff --git a/src/network/kernel/qhostinfo_p.h b/src/network/kernel/qhostinfo_p.h index 79fad84..909bd03 100644 --- a/src/network/kernel/qhostinfo_p.h +++ b/src/network/kernel/qhostinfo_p.h @@ -228,7 +228,7 @@ public: QSymbianHostResolver(const QString &hostName, int id); ~QSymbianHostResolver(); - QHostInfo requestHostLookup(); + void requestHostLookup(); int id(); QHostInfoResult resultEmitter; @@ -258,7 +258,8 @@ private: enum { EIdle, EGetByName, - EGetByAddress + EGetByAddress, + EError } iState; }; diff --git a/src/network/kernel/qhostinfo_symbian.cpp b/src/network/kernel/qhostinfo_symbian.cpp index ad5f38a..54ec33c 100644 --- a/src/network/kernel/qhostinfo_symbian.cpp +++ b/src/network/kernel/qhostinfo_symbian.cpp @@ -233,7 +233,7 @@ QSymbianHostResolver::~QSymbianHostResolver() } // Async equivalent to QHostInfoAgent::fromName() -QHostInfo QSymbianHostResolver::requestHostLookup() +void QSymbianHostResolver::requestHostLookup() { #if defined(QHOSTINFO_DEBUG) @@ -245,45 +245,51 @@ QHostInfo QSymbianHostResolver::requestHostLookup() if (err) { // What are we doing with iResults?? iResults.setError(QHostInfo::UnknownError); - iResults.setErrorString(QObject::tr("Symbian error code: %1").arg(err)); + iResults.setErrorString(QSystemError(err, QSystemError::NativeError).toString()); - iHostResolver.Close(); - return iResults; - } + } else { - if (iAddress.setAddress(iHostName)) { - // Reverse lookup + if (iAddress.setAddress(iHostName)) { + // Reverse lookup - TInetAddr IpAdd; - IpAdd.Input(qt_QString2TPtrC(iHostName)); + TInetAddr IpAdd; + IpAdd.Input(qt_QString2TPtrC(iHostName)); - // Asynchronous request. - iHostResolver.GetByAddress(IpAdd, iNameResult, iStatus); // <---- ASYNC - iState = EGetByAddress; + // Asynchronous request. + iHostResolver.GetByAddress(IpAdd, iNameResult, iStatus); // <---- ASYNC + iState = EGetByAddress; - } else { + } else { - // IDN support - QByteArray aceHostname = QUrl::toAce(iHostName); - iResults.setHostName(iHostName); - if (aceHostname.isEmpty()) { - iResults.setError(QHostInfo::HostNotFound); - iResults.setErrorString(iHostName.isEmpty() ? - QCoreApplication::translate("QHostInfoAgent", "No host name given") : - QCoreApplication::translate("QHostInfoAgent", "Invalid hostname")); + // IDN support + QByteArray aceHostname = QUrl::toAce(iHostName); + iResults.setHostName(iHostName); + if (aceHostname.isEmpty()) { + iResults.setError(QHostInfo::HostNotFound); + iResults.setErrorString(iHostName.isEmpty() ? + QCoreApplication::translate("QHostInfoAgent", "No host name given") : + QCoreApplication::translate("QHostInfoAgent", "Invalid hostname")); - iHostResolver.Close(); - return iResults; - } + err = KErrArgument; + } else { - // Asynchronous request. - iHostResolver.GetByName(qt_QString2TPtrC(QString::fromLatin1(aceHostname)), iNameResult, iStatus); - iState = EGetByName; + // Asynchronous request. + iHostResolver.GetByName(qt_QString2TPtrC(QString::fromLatin1(aceHostname)), iNameResult, iStatus); + iState = EGetByName; + } + } } - SetActive(); + if (err) { + iHostResolver.Close(); - return iResults; + //self complete so that RunL can inform manager without causing recursion + iState = EError; + iStatus = KRequestPending; + SetActive(); + TRequestStatus* stat = &iStatus; + User::RequestComplete(stat, err); + } } void QSymbianHostResolver::DoCancel() -- cgit v0.12 From e29e13ff537a92f7d2afe34893d8bae8a6788bed Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 18 Mar 2011 11:45:52 +0000 Subject: Add explicit network session support for async QHostInfo Pass the shared network session pointer into the QSymbianHostResolver (which maintains a reference for its lifetime). This is used to open the RHostResolver handle, in order to get a host resolver which is associated with a particular session. The session is obtained from the _q_networksession property of the QAbstractSocket, as in the symbian socket engine Reviewed-by: Markus Goetz --- src/network/kernel/qhostinfo.cpp | 10 +++++++++- src/network/kernel/qhostinfo_p.h | 3 ++- src/network/kernel/qhostinfo_symbian.cpp | 18 +++++++++++++++--- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/network/kernel/qhostinfo.cpp b/src/network/kernel/qhostinfo.cpp index 7a15a05..1ae0bbd 100644 --- a/src/network/kernel/qhostinfo.cpp +++ b/src/network/kernel/qhostinfo.cpp @@ -49,6 +49,7 @@ #include #include #include +#include #ifdef Q_OS_UNIX # include @@ -219,8 +220,15 @@ int QHostInfo::lookupHost(const QString &name, QObject *receiver, } // cache is not enabled or it was not in the cache, do normal lookup +#ifndef QT_NO_BEARERMANAGEMENT + QSharedPointer networkSession; + QVariant v(receiver->property("_q_networksession")); + if (v.isValid()) + networkSession = qvariant_cast< QSharedPointer >(v); +#endif + QSymbianHostResolver *symbianResolver = 0; - QT_TRAP_THROWING(symbianResolver = new QSymbianHostResolver(name, id)); + QT_TRAP_THROWING(symbianResolver = new QSymbianHostResolver(name, id, networkSession)); QObject::connect(&symbianResolver->resultEmitter, SIGNAL(resultsReady(QHostInfo)), receiver, member, Qt::QueuedConnection); manager->scheduleLookup(symbianResolver); } diff --git a/src/network/kernel/qhostinfo_p.h b/src/network/kernel/qhostinfo_p.h index 909bd03..e3f7f19 100644 --- a/src/network/kernel/qhostinfo_p.h +++ b/src/network/kernel/qhostinfo_p.h @@ -225,7 +225,7 @@ private slots: class QSymbianHostResolver : public CActive { public: - QSymbianHostResolver(const QString &hostName, int id); + QSymbianHostResolver(const QString &hostName, int id, QSharedPointer networkSession); ~QSymbianHostResolver(); void requestHostLookup(); @@ -247,6 +247,7 @@ private: RSocketServ& iSocketServ; RHostResolver iHostResolver; + QSharedPointer iNetworkSession; TRequestStatus iStatus; diff --git a/src/network/kernel/qhostinfo_symbian.cpp b/src/network/kernel/qhostinfo_symbian.cpp index 54ec33c..12e59c6 100644 --- a/src/network/kernel/qhostinfo_symbian.cpp +++ b/src/network/kernel/qhostinfo_symbian.cpp @@ -51,6 +51,7 @@ #include "qhostinfo_p.h" #include #include +#include QT_BEGIN_NAMESPACE @@ -216,9 +217,9 @@ QString QHostInfo::localDomainName() } -QSymbianHostResolver::QSymbianHostResolver(const QString &hostName, int identifier) +QSymbianHostResolver::QSymbianHostResolver(const QString &hostName, int identifier, QSharedPointer networkSession) : CActive(CActive::EPriorityStandard), iHostName(hostName), - iSocketServ(qt_symbianGetSocketServer()), iResults(identifier) + iSocketServ(qt_symbianGetSocketServer()), iNetworkSession(networkSession), iResults(identifier) { CActiveScheduler::Add(this); } @@ -241,7 +242,18 @@ void QSymbianHostResolver::requestHostLookup() iHostName.toLatin1().constData(), id()); #endif - int err = iHostResolver.Open(iSocketServ, KAfInet, KProtocolInetUdp); + int err; + if (iNetworkSession) { + err = QNetworkSessionPrivate::nativeOpenHostResolver(*iNetworkSession, iHostResolver, KAfInet, KProtocolInetUdp); +#if defined(QHOSTINFO_DEBUG) + qDebug("using resolver from session (err = %d)", err); +#endif + } else { + err = iHostResolver.Open(iSocketServ, KAfInet, KProtocolInetUdp); +#if defined(QHOSTINFO_DEBUG) + qDebug("using default resolver (err = %d)", err); +#endif + } if (err) { // What are we doing with iResults?? iResults.setError(QHostInfo::UnknownError); -- cgit v0.12 From 67c6737c6702506b5b09fd84389e20ba539cc000 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 21 Mar 2011 17:12:56 +0000 Subject: Fix bugs where = used instead of == Reviewed-by: Aaron Tunney --- src/network/kernel/qhostinfo_symbian.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/network/kernel/qhostinfo_symbian.cpp b/src/network/kernel/qhostinfo_symbian.cpp index 12e59c6..347bf67 100644 --- a/src/network/kernel/qhostinfo_symbian.cpp +++ b/src/network/kernel/qhostinfo_symbian.cpp @@ -101,7 +101,7 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName, QSharedPointerid()) { + if (id == iCurrentLookups[i]->id()) { QSymbianHostResolver* r = iCurrentLookups[i]; iCurrentLookups.Remove(i); r->Cancel(); @@ -526,7 +526,7 @@ void QSymbianHostInfoLookupManger::abortLookup(int id) } // Then in the scheduled lookups. for (i = 0; i < iScheduledLookups.Count(); i++) { - if (id = iScheduledLookups[i]->id()) { + if (id == iScheduledLookups[i]->id()) { QSymbianHostResolver* r = iScheduledLookups[i]; iScheduledLookups.Remove(i); delete r; -- cgit v0.12 From 40fc1a3ca3b7050f317513cf69dd89a01479e098 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 21 Mar 2011 18:53:42 +0000 Subject: Implement network session support for synchronous QHostInfo Private API, QHostInfoPrivate::fromName, which is called from QAbstractSocket when the network session property is set. Reviewed-by: Markus Goetz --- src/network/kernel/qhostinfo.cpp | 14 ++++++++++++++ src/network/kernel/qhostinfo_p.h | 5 +++++ src/network/kernel/qhostinfo_symbian.cpp | 15 +++++---------- src/network/socket/qabstractsocket.cpp | 9 +++++++++ 4 files changed, 33 insertions(+), 10 deletions(-) diff --git a/src/network/kernel/qhostinfo.cpp b/src/network/kernel/qhostinfo.cpp index 1ae0bbd..aff55d9 100644 --- a/src/network/kernel/qhostinfo.cpp +++ b/src/network/kernel/qhostinfo.cpp @@ -272,6 +272,20 @@ QHostInfo QHostInfo::fromName(const QString &name) return hostInfo; } +#ifndef QT_NO_BEARERMANAGEMENT +QHostInfo QHostInfoPrivate::fromName(const QString &name, QSharedPointer session) +{ +#if defined QHOSTINFO_DEBUG + qDebug("QHostInfoPrivate::fromName(\"%s\") with session %p",name.toLatin1().constData(), session.data()); +#endif + + QHostInfo hostInfo = QHostInfoAgent::fromName(name, session); + QAbstractHostInfoLookupManger* manager = theHostInfoLookupManager(); + manager->cache.put(name, hostInfo); + return hostInfo; +} +#endif + /*! \enum QHostInfo::HostInfoError diff --git a/src/network/kernel/qhostinfo_p.h b/src/network/kernel/qhostinfo_p.h index e3f7f19..a40104a 100644 --- a/src/network/kernel/qhostinfo_p.h +++ b/src/network/kernel/qhostinfo_p.h @@ -70,6 +70,7 @@ #include #include +#include #ifdef Q_OS_SYMBIAN // Symbian Headers @@ -117,6 +118,10 @@ public: lookupId(0) { } +#ifndef QT_NO_BEARERMANAGEMENT + //not a public API yet + static QHostInfo fromName(const QString &hostName, QSharedPointer networkSession); +#endif QHostInfo::HostInfoError err; QString errorStr; diff --git a/src/network/kernel/qhostinfo_symbian.cpp b/src/network/kernel/qhostinfo_symbian.cpp index 347bf67..65c3d62 100644 --- a/src/network/kernel/qhostinfo_symbian.cpp +++ b/src/network/kernel/qhostinfo_symbian.cpp @@ -66,16 +66,11 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName, QSharedPointer #include @@ -1786,6 +1787,14 @@ bool QAbstractSocket::waitForConnected(int msecs) #endif QHostInfo::abortHostLookup(d->hostLookupId); d->hostLookupId = -1; +#ifndef QT_NO_BEARERMANAGEMENT + QSharedPointer networkSession; + QVariant v(property("_q_networksession")); + if (v.isValid()) { + networkSession = qvariant_cast< QSharedPointer >(v); + d->_q_startConnecting(QHostInfoPrivate::fromName(d->hostName, networkSession)); + } else +#endif d->_q_startConnecting(QHostInfo::fromName(d->hostName)); } if (state() == UnconnectedState) -- cgit v0.12 From c9edb126e6f01e54dfbb1e952b253b2490d26e88 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 21 Mar 2011 18:56:13 +0000 Subject: Fix SetActive being called twice Reviewed-by: Markus Goetz --- src/network/kernel/qhostinfo_symbian.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/network/kernel/qhostinfo_symbian.cpp b/src/network/kernel/qhostinfo_symbian.cpp index 65c3d62..ca76b12 100644 --- a/src/network/kernel/qhostinfo_symbian.cpp +++ b/src/network/kernel/qhostinfo_symbian.cpp @@ -292,8 +292,6 @@ void QSymbianHostResolver::requestHostLookup() //self complete so that RunL can inform manager without causing recursion iState = EError; - iStatus = KRequestPending; - SetActive(); TRequestStatus* stat = &iStatus; User::RequestComplete(stat, err); } -- cgit v0.12 From 919e282ff62171654dd60875fe1c058f36a14584 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 21 Mar 2011 18:57:16 +0000 Subject: Fix a deadlock in symbian QHostInfo when aborting DoCancel was calling lookupFinished, which tries to acquire a mutex again that was already acquired in abortLookup (causing a deadlock). This call is un-necessary, as Cancel was only called from the destructor and from abortLookup - in neither case is this wanted. The run and RunError functions explicitly call lookupFinished. This fixes hang in autotests when attempting to lookup a bad host name. Reviewed-by: Markus Goetz --- src/network/kernel/qhostinfo_symbian.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/network/kernel/qhostinfo_symbian.cpp b/src/network/kernel/qhostinfo_symbian.cpp index ca76b12..c969748 100644 --- a/src/network/kernel/qhostinfo_symbian.cpp +++ b/src/network/kernel/qhostinfo_symbian.cpp @@ -299,8 +299,6 @@ void QSymbianHostResolver::requestHostLookup() void QSymbianHostResolver::DoCancel() { - QSymbianHostInfoLookupManger *manager = QSymbianHostInfoLookupManger::globalInstance(); - manager->lookupFinished(this); iHostResolver.Cancel(); } @@ -512,7 +510,7 @@ void QSymbianHostInfoLookupManger::abortLookup(int id) if (id == iCurrentLookups[i]->id()) { QSymbianHostResolver* r = iCurrentLookups[i]; iCurrentLookups.Remove(i); - r->Cancel(); + delete r; //cancels via destructor runNextLookup(); return; } -- cgit v0.12 From 32a43ac64aee529c55af77edbbe34c54cb8f5e52 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 21 Mar 2011 19:03:56 +0000 Subject: Report correct error from QSymbianSocketEngine::nativeSelect Sometimes the error is in the return code from the ioctl, other times it is in the select last error getopt. Treat both error sources the same way and call setError. Return code has higher priority. Reviewed-by: Markus Goetz --- src/network/socket/qsymbiansocketengine.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index 07b2e5a..58e8d9f 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -1137,14 +1137,14 @@ int QSymbianSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool #ifdef QNATIVESOCKETENGINE_DEBUG qDebug() << "QSymbianSocketEnginePrivate::nativeSelect: select status" << selectStat.Int() << (int)selectFlags(); #endif - if (selectStat != KErrNone) - return selectStat.Int(); - if (selectFlags() & KSockSelectExcept) { - TInt err; + TInt err = selectStat.Int(); + if (!err && (selectFlags() & KSockSelectExcept)) { nativeSocket.GetOpt(KSOSelectLastError, KSOLSocket, err); #ifdef QNATIVESOCKETENGINE_DEBUG qDebug() << "QSymbianSocketEnginePrivate::nativeSelect: select last error" << err; #endif + } + if (err) { //TODO: avoidable cast? //set the error here, because read won't always return the same error again as select. const_cast(this)->setError(err); -- cgit v0.12 From 3c94f70a2e2c8e9f6a6cfc952837f18568c9bc4c Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 21 Mar 2011 20:07:32 +0000 Subject: Fix crashing debug message When testing the socks5 socket engine, it closes the socket from within _q_controlSocketError. Frequently a data abort occurs after this when printing the debug message. Moved the debug message before emitting the signal to avoid this. Reviewed-by: Markus Goetz --- src/network/socket/qabstractsocket.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/network/socket/qabstractsocket.cpp b/src/network/socket/qabstractsocket.cpp index 801556e..9c96e1c 100644 --- a/src/network/socket/qabstractsocket.cpp +++ b/src/network/socket/qabstractsocket.cpp @@ -752,11 +752,11 @@ bool QAbstractSocketPrivate::flush() if (written < 0) { socketError = socketEngine->error(); q->setErrorString(socketEngine->errorString()); - emit q->error(socketError); - // an unexpected error so close the socket. #if defined (QABSTRACTSOCKET_DEBUG) qDebug() << "QAbstractSocketPrivate::flush() write error, aborting." << socketEngine->errorString(); #endif + emit q->error(socketError); + // an unexpected error so close the socket. q->abort(); return false; } -- cgit v0.12 From 747d43b89c9230d12a81e77e390f4f422f5255db Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Tue, 22 Mar 2011 12:17:05 +0100 Subject: QHostInfo: Fix compilation with non-symbian Reviewed-by: Shane Kearns --- src/network/kernel/qhostinfo.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/network/kernel/qhostinfo.cpp b/src/network/kernel/qhostinfo.cpp index aff55d9..3413c9b 100644 --- a/src/network/kernel/qhostinfo.cpp +++ b/src/network/kernel/qhostinfo.cpp @@ -286,6 +286,15 @@ QHostInfo QHostInfoPrivate::fromName(const QString &name, QSharedPointer networkSession) +{ + return QHostInfoAgent::fromName(hostName); +} +#endif + + /*! \enum QHostInfo::HostInfoError -- cgit v0.12 From 3f4dca824126a2d5e7d31e122a16118b79ef78d8 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 22 Mar 2011 11:55:15 +0000 Subject: Fixes to QSystemError 1. KErrNotReady message changed to have one file and one network example 2. Format error for the generic error code was generating a QWARN Reviewed-by: Markus Goetz --- src/corelib/kernel/qsystemerror.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/corelib/kernel/qsystemerror.cpp b/src/corelib/kernel/qsystemerror.cpp index 953ed95..5cf8fc6 100644 --- a/src/corelib/kernel/qsystemerror.cpp +++ b/src/corelib/kernel/qsystemerror.cpp @@ -154,7 +154,7 @@ static QString symbianErrorString(int errorCode) case KErrInUse: return QLatin1String("in use"); case KErrNotReady: - return QLatin1String("not ready (e.g. FS dismounted, no memory card)"); + return QLatin1String("not ready (e.g. FS dismounted, network down)"); case KErrCorrupt: return QLatin1String("corrupt"); case KErrAccessDenied: @@ -190,7 +190,7 @@ static QString symbianErrorString(int errorCode) case KErrPermissionDenied: return QLatin1String("permission denied"); default: - return QString(QLatin1String("symbian error %d")).arg(errorCode); + return QString(QLatin1String("symbian error %1")).arg(errorCode); } } #endif -- cgit v0.12 From f31dfc682402396e35dffd8952eb5ced8f6b4030 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 22 Mar 2011 17:46:39 +0000 Subject: Fix event loop hangs caused by async QHostInfo Declaring iStatus in a derived class hides the iStatus in CActive. This confuses the active scheduler (which is using CActive::iStatus) and would in a normal symbian application have caused a stray signal panic. However as Qt's event loop integration uses CActiveScheduler::RunIfReady instead of the normal CActiveScheduler::Start the panic does not happen. Instead the thread semaphore gets messed up and causes problems. Reviewed-by: Markus Goetz --- src/network/kernel/qhostinfo_p.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/network/kernel/qhostinfo_p.h b/src/network/kernel/qhostinfo_p.h index a40104a..bff5fc4 100644 --- a/src/network/kernel/qhostinfo_p.h +++ b/src/network/kernel/qhostinfo_p.h @@ -254,8 +254,6 @@ private: RHostResolver iHostResolver; QSharedPointer iNetworkSession; - TRequestStatus iStatus; - TNameEntry iNameResult; QHostAddress iAddress; -- cgit v0.12 From 1831e7f802d1bdba33f320c21f29df02d647ead8 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 22 Mar 2011 17:59:05 +0000 Subject: Ensure parameters of async function calls stay in scope Calling symbian asynchronous functions with parameters on the stack, even "in" parameters is unsafe. If the server is blocked on another operation, then it will not read the parameters until later (at which time the stack is invalid) Reviewed-by: Markus Goetz --- src/network/kernel/qhostinfo_p.h | 4 ++++ src/network/kernel/qhostinfo_symbian.cpp | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/network/kernel/qhostinfo_p.h b/src/network/kernel/qhostinfo_p.h index bff5fc4..71c191f 100644 --- a/src/network/kernel/qhostinfo_p.h +++ b/src/network/kernel/qhostinfo_p.h @@ -249,12 +249,16 @@ private: private: const QString iHostName; + QString iEncodedHostName; + TPtrC iHostNamePtr; RSocketServ& iSocketServ; RHostResolver iHostResolver; QSharedPointer iNetworkSession; TNameEntry iNameResult; + TInetAddr IpAdd; + QHostAddress iAddress; QHostInfo iResults; diff --git a/src/network/kernel/qhostinfo_symbian.cpp b/src/network/kernel/qhostinfo_symbian.cpp index c969748..c1457fd 100644 --- a/src/network/kernel/qhostinfo_symbian.cpp +++ b/src/network/kernel/qhostinfo_symbian.cpp @@ -259,7 +259,6 @@ void QSymbianHostResolver::requestHostLookup() if (iAddress.setAddress(iHostName)) { // Reverse lookup - TInetAddr IpAdd; IpAdd.Input(qt_QString2TPtrC(iHostName)); // Asynchronous request. @@ -279,9 +278,11 @@ void QSymbianHostResolver::requestHostLookup() err = KErrArgument; } else { + iEncodedHostName = QString::fromLatin1(aceHostname); + iHostNamePtr.Set(qt_QString2TPtrC(iEncodedHostName)); // Asynchronous request. - iHostResolver.GetByName(qt_QString2TPtrC(QString::fromLatin1(aceHostname)), iNameResult, iStatus); + iHostResolver.GetByName(iHostNamePtr, iNameResult, iStatus); iState = EGetByName; } } -- cgit v0.12 From 4f74076095add88c936e729838c9205abfe04bd0 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 22 Mar 2011 18:09:13 +0000 Subject: Ensure QSymbianHostResolver::DoCancel does correct thing based on state If a host resolver async call in progress, cancel it. Otherwise don't. Reviewed-by: Markus Goetz --- src/network/kernel/qhostinfo_symbian.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/network/kernel/qhostinfo_symbian.cpp b/src/network/kernel/qhostinfo_symbian.cpp index c1457fd..fdb0fbc 100644 --- a/src/network/kernel/qhostinfo_symbian.cpp +++ b/src/network/kernel/qhostinfo_symbian.cpp @@ -300,7 +300,16 @@ void QSymbianHostResolver::requestHostLookup() void QSymbianHostResolver::DoCancel() { - iHostResolver.Cancel(); +#if defined(QHOSTINFO_DEBUG) + qDebug() << "QSymbianHostResolver::DoCancel" << QThread::currentThreadId() << id() << (int)iState << this; +#endif + if (iState == EGetByAddress || iState == EGetByName) { + //these states have made an async request to host resolver + iHostResolver.Cancel(); + } else { + //for the self completing states there is nothing to cancel + Q_ASSERT(iState == EError); + } } void QSymbianHostResolver::RunL() -- cgit v0.12 From 999f44f06702513747844bcc0809597134be5e78 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 22 Mar 2011 18:16:45 +0000 Subject: use QList instead of RPointerArray For maintainability, it's better to use Qt's container classes Reviewed-by: Markus Goetz --- src/network/kernel/qhostinfo_p.h | 5 ++-- src/network/kernel/qhostinfo_symbian.cpp | 49 ++++++++++++++++---------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/network/kernel/qhostinfo_p.h b/src/network/kernel/qhostinfo_p.h index 71c191f..a7e83da 100644 --- a/src/network/kernel/qhostinfo_p.h +++ b/src/network/kernel/qhostinfo_p.h @@ -295,9 +295,8 @@ private: static const int KMaxConcurrentLookups = 5; - RPointerArray iCurrentLookups; - RPointerArray iScheduledLookups; - RPointerArray iFinishedLookups; + QList iCurrentLookups; + QList iScheduledLookups; QMutex mutex; }; diff --git a/src/network/kernel/qhostinfo_symbian.cpp b/src/network/kernel/qhostinfo_symbian.cpp index fdb0fbc..5998a72 100644 --- a/src/network/kernel/qhostinfo_symbian.cpp +++ b/src/network/kernel/qhostinfo_symbian.cpp @@ -435,15 +435,18 @@ QSymbianHostInfoLookupManger::QSymbianHostInfoLookupManger() QSymbianHostInfoLookupManger::~QSymbianHostInfoLookupManger() { - iCurrentLookups.Close(); - iScheduledLookups.Close(); } void QSymbianHostInfoLookupManger::clear() { QMutexLocker locker(&mutex); - iCurrentLookups.ResetAndDestroy(); - iScheduledLookups.ResetAndDestroy(); +#if defined(QHOSTINFO_DEBUG) + qDebug() << "QSymbianHostInfoLookupManger::clear" << QThread::currentThreadId(); +#endif + //TODO: these aren't deleted because of thread unsafety, but that is a behaviour difference + //qDeleteAll(iCurrentLookups); + //qDeleteAll(iScheduledLookups); + cache.clear(); } void QSymbianHostInfoLookupManger::lookupFinished(QSymbianHostResolver *r) @@ -451,13 +454,13 @@ void QSymbianHostInfoLookupManger::lookupFinished(QSymbianHostResolver *r) QMutexLocker locker(&mutex); #if defined(QHOSTINFO_DEBUG) - qDebug() << "QSymbianHostInfoLookupManger::lookupFinished" << r->id() << "current" << iCurrentLookups.Count() << "queued" << iScheduledLookups.Count(); + qDebug() << "QSymbianHostInfoLookupManger::lookupFinished" << QThread::currentThreadId() << r->id() << "current" << iCurrentLookups.count() << "queued" << iScheduledLookups.count(); #endif // remove finished lookup from array and destroy - TInt count = iCurrentLookups.Count(); + TInt count = iCurrentLookups.count(); for (TInt i = 0; i < count; i++) { if (iCurrentLookups[i]->id() == r->id()) { - iCurrentLookups.Remove(i); + iCurrentLookups.removeAt(i); break; } } @@ -468,15 +471,14 @@ void QSymbianHostInfoLookupManger::lookupFinished(QSymbianHostResolver *r) void QSymbianHostInfoLookupManger::runNextLookup() { #if defined(QHOSTINFO_DEBUG) - qDebug() << "QSymbianHostInfoLookupManger::runNextLookup" << "current" << iCurrentLookups.Count() << "queued" << iScheduledLookups.Count(); + qDebug() << "QSymbianHostInfoLookupManger::runNextLookup" << QThread::currentThreadId() << "current" << iCurrentLookups.count() << "queued" << iScheduledLookups.count(); #endif // check to see if there are any scheduled lookups - if (iScheduledLookups.Count() > 0) { + if (iScheduledLookups.count() > 0) { // if so, move one to the current lookups and run it // FIFO - QSymbianHostResolver* hostResolver = iScheduledLookups[0]; - iCurrentLookups.Append(hostResolver); - iScheduledLookups.Remove(0); + QSymbianHostResolver* hostResolver = iScheduledLookups.takeFirst(); + iCurrentLookups.append(hostResolver); hostResolver->requestHostLookup(); } } @@ -487,19 +489,19 @@ void QSymbianHostInfoLookupManger::scheduleLookup(QSymbianHostResolver* r) QMutexLocker locker(&mutex); #if defined(QHOSTINFO_DEBUG) - qDebug() << "QSymbianHostInfoLookupManger::scheduleLookup" << r->id() << "current" << iCurrentLookups.Count() << "queued" << iScheduledLookups.Count(); + qDebug() << "QSymbianHostInfoLookupManger::scheduleLookup" << QThread::currentThreadId() << r->id() << "current" << iCurrentLookups.count() << "queued" << iScheduledLookups.count(); #endif // Check to see if we have space on the current lookups pool. - if (iCurrentLookups.Count() >= KMaxConcurrentLookups) { + if (iCurrentLookups.count() >= KMaxConcurrentLookups) { // If no, schedule for later. - iScheduledLookups.Append(r); + iScheduledLookups.append(r); #if defined(QHOSTINFO_DEBUG) qDebug(" - scheduled"); #endif return; } else { // If yes, add it to the current lookups. - iCurrentLookups.Append(r); + iCurrentLookups.append(r); // ... and trigger the async call. r->requestHostLookup(); @@ -511,32 +513,31 @@ void QSymbianHostInfoLookupManger::abortLookup(int id) QMutexLocker locker(&mutex); #if defined(QHOSTINFO_DEBUG) - qDebug() << "QSymbianHostInfoLookupManger::abortLookup" << id << "current" << iCurrentLookups.Count() << "queued" << iScheduledLookups.Count(); + qDebug() << "QSymbianHostInfoLookupManger::abortLookup" << QThread::currentThreadId() << id << "current" << iCurrentLookups.count() << "queued" << iScheduledLookups.count(); #endif int i = 0; // Find the aborted lookup by ID. // First in the current lookups. - for (i = 0; i < iCurrentLookups.Count(); i++) { + for (i = 0; i < iCurrentLookups.count(); i++) { if (id == iCurrentLookups[i]->id()) { - QSymbianHostResolver* r = iCurrentLookups[i]; - iCurrentLookups.Remove(i); + QSymbianHostResolver* r = iCurrentLookups.at(i); + iCurrentLookups.removeAt(i); delete r; //cancels via destructor runNextLookup(); return; } } // Then in the scheduled lookups. - for (i = 0; i < iScheduledLookups.Count(); i++) { + for (i = 0; i < iScheduledLookups.count(); i++) { if (id == iScheduledLookups[i]->id()) { - QSymbianHostResolver* r = iScheduledLookups[i]; - iScheduledLookups.Remove(i); + QSymbianHostResolver* r = iScheduledLookups.at(i); + iScheduledLookups.removeAt(i); delete r; return; } } } - QSymbianHostInfoLookupManger* QSymbianHostInfoLookupManger::globalInstance() { return static_cast -- cgit v0.12 From aacdf24477bbcddd6492c3bac3d903555f09297a Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 22 Mar 2011 18:19:17 +0000 Subject: Fix bugs in tst_qnetworkreply It used a unix way to delete local servers. Changed this to the cross platform QLocalServer::removeServer API It reported XPASS on symbian due to SRCDIR being a relative path not absolute. (added a check for this, as SRCDIR could be relative on windows) Also fixed a couple of compiler warnings Reviewed-by: Martin Petersson --- tests/auto/qnetworkreply/tst_qnetworkreply.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp index ffe7ea4..f8a9530 100644 --- a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp @@ -1542,7 +1542,7 @@ void tst_QNetworkReply::getErrors() QNetworkRequest request(url); #if defined(Q_OS_WIN) || defined (Q_OS_SYMBIAN) - if (qstrcmp(QTest::currentDataTag(), "empty-scheme-host") == 0) + if (qstrcmp(QTest::currentDataTag(), "empty-scheme-host") == 0 && QFileInfo(url).isAbsolute()) QTest::ignoreMessage(QtWarningMsg, "QNetworkAccessFileBackendFactory: URL has no schema set, use file:// for files"); #endif @@ -1561,7 +1561,8 @@ void tst_QNetworkReply::getErrors() QFETCH(int, error); #if defined(Q_OS_WIN) || defined (Q_OS_SYMBIAN) - QEXPECT_FAIL("empty-scheme-host", "this is expected to fail on Windows and Symbian, QTBUG-17731", Abort); + if (QFileInfo(url).isAbsolute()) + QEXPECT_FAIL("empty-scheme-host", "this is expected to fail on Windows and Symbian, QTBUG-17731", Abort); #endif QEXPECT_FAIL("ftp-is-dir", "QFtp cannot provide enough detail", Abort); // the line below is not necessary @@ -3210,8 +3211,7 @@ void tst_QNetworkReply::ioPutToFileFromLocalSocket() QString socketname = "networkreplytest"; QLocalServer server; if (!server.listen(socketname)) { - if (QFile::exists(server.fullServerName())) - QFile::remove(server.fullServerName()); + QLocalServer::removeServer(socketname); QVERIFY(server.listen(socketname)); } QLocalSocket active; @@ -3256,7 +3256,7 @@ void tst_QNetworkReply::ioPutToFileFromProcess() { #if defined(Q_OS_WINCE) || defined (Q_OS_SYMBIAN) QSKIP("Currently no stdin/out supported for Windows CE / Symbian OS", SkipAll); -#endif +#else #ifdef Q_OS_WIN if (qstrcmp(QTest::currentDataTag(), "small") == 0) @@ -3294,6 +3294,7 @@ void tst_QNetworkReply::ioPutToFileFromProcess() QByteArray contents = file.readAll(); QCOMPARE(contents, data); #endif +#endif } void tst_QNetworkReply::ioPutToFtpFromFile_data() @@ -5088,7 +5089,7 @@ void tst_QNetworkReply::getFromHttpIntoBuffer() // FIXME we really need to consolidate all those server implementations class GetFromHttpIntoBuffer2Server : QObject { - Q_OBJECT; + Q_OBJECT qint64 dataSize; qint64 dataSent; QTcpServer server; -- cgit v0.12 From 263be570b498847e0762831a5e6a29e1056b4b57 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Wed, 23 Mar 2011 13:29:25 +0000 Subject: Update Symbian .def files --- src/s60installs/bwins/QtCoreu.def | 28 ++++++++++- src/s60installs/bwins/QtGuiu.def | 26 ++++++++++ src/s60installs/bwins/QtNetworku.def | 5 ++ src/s60installs/bwins/QtTestu.def | 89 ++++++++++++++++++++++++++++++++++ src/s60installs/eabi/QtCoreu.def | 30 +++++++++++- src/s60installs/eabi/QtGuiu.def | 20 ++++++++ src/s60installs/eabi/QtNetworku.def | 5 ++ src/s60installs/eabi/QtTestu.def | 94 ++++++++++++++++++++++++++++++++++++ 8 files changed, 293 insertions(+), 4 deletions(-) diff --git a/src/s60installs/bwins/QtCoreu.def b/src/s60installs/bwins/QtCoreu.def index dd7d588..33f22ee 100644 --- a/src/s60installs/bwins/QtCoreu.def +++ b/src/s60installs/bwins/QtCoreu.def @@ -1380,7 +1380,7 @@ EXPORTS ?create@QAbstractFileEngine@@SAPAV1@ABVQString@@@Z @ 1379 NONAME ; class QAbstractFileEngine * QAbstractFileEngine::create(class QString const &) ?create@QNonContiguousByteDeviceFactory@@SAPAVQNonContiguousByteDevice@@PAVQByteArray@@@Z @ 1380 NONAME ; class QNonContiguousByteDevice * QNonContiguousByteDeviceFactory::create(class QByteArray *) ?create@QNonContiguousByteDeviceFactory@@SAPAVQNonContiguousByteDevice@@PAVQIODevice@@@Z @ 1381 NONAME ; class QNonContiguousByteDevice * QNonContiguousByteDeviceFactory::create(class QIODevice *) - ?create@QNonContiguousByteDeviceFactory@@SAPAVQNonContiguousByteDevice@@PAVQRingBuffer@@@Z @ 1382 NONAME ; class QNonContiguousByteDevice * QNonContiguousByteDeviceFactory::create(class QRingBuffer *) + ?create@QNonContiguousByteDeviceFactory@@SAPAVQNonContiguousByteDevice@@PAVQRingBuffer@@@Z @ 1382 NONAME ABSENT ; class QNonContiguousByteDevice * QNonContiguousByteDeviceFactory::create(class QRingBuffer *) ?create@QSharedMemory@@QAE_NHW4AccessMode@1@@Z @ 1383 NONAME ; bool QSharedMemory::create(int, enum QSharedMemory::AccessMode) ?create@QTextCodecPlugin@@EAEPAVQTextCodec@@ABVQString@@@Z @ 1384 NONAME ; class QTextCodec * QTextCodecPlugin::create(class QString const &) ?create@QVariant@@IAEXHPBX@Z @ 1385 NONAME ; void QVariant::create(int, void const *) @@ -3572,7 +3572,7 @@ EXPORTS ?skipWhiteSpace@QTextStream@@QAEXXZ @ 3571 NONAME ; void QTextStream::skipWhiteSpace(void) ?sleep@QThread@@KAXK@Z @ 3572 NONAME ; void QThread::sleep(unsigned long) ?socket@QSocketNotifier@@QBEHXZ @ 3573 NONAME ; int QSocketNotifier::socket(void) const - ?socketFired@QEventDispatcherSymbian@@QAEXPAVQSocketActiveObject@@@Z @ 3574 NONAME ; void QEventDispatcherSymbian::socketFired(class QSocketActiveObject *) + ?socketFired@QEventDispatcherSymbian@@QAEXPAVQSocketActiveObject@@@Z @ 3574 NONAME ABSENT ; void QEventDispatcherSymbian::socketFired(class QSocketActiveObject *) ?sort@QAbstractItemModel@@UAEXHW4SortOrder@Qt@@@Z @ 3575 NONAME ; void QAbstractItemModel::sort(int, enum Qt::SortOrder) ?sorting@QDir@@QBE?AV?$QFlags@W4SortFlag@QDir@@@@XZ @ 3576 NONAME ; class QFlags QDir::sorting(void) const ?sourceState@QAbstractTransition@@QBEPAVQState@@XZ @ 3577 NONAME ; class QState * QAbstractTransition::sourceState(void) const @@ -4605,4 +4605,28 @@ EXPORTS ?hasError@QXmlStreamWriter@@QBE_NXZ @ 4604 NONAME ; bool QXmlStreamWriter::hasError(void) const ?revision@QMetaProperty@@QBEHXZ @ 4605 NONAME ; int QMetaProperty::revision(void) const ?revision@QMetaMethod@@QBEHXZ @ 4606 NONAME ; int QMetaMethod::revision(void) const + gzungetc @ 4607 NONAME + ?addSocket@QSymbianSocketManager@@QAEHABVRSocket@@@Z @ 4608 NONAME ; int QSymbianSocketManager::addSocket(class RSocket const &) + ??0QActiveObject@@QAE@HPAVQEventDispatcherSymbian@@@Z @ 4609 NONAME ; QActiveObject::QActiveObject(int, class QEventDispatcherSymbian *) + ?setDefaultConnection@QSymbianSocketManager@@QAEXPAVRConnection@@@Z @ 4610 NONAME ; void QSymbianSocketManager::setDefaultConnection(class RConnection *) + ?reactivateAndComplete@QActiveObject@@QAEXXZ @ 4611 NONAME ; void QActiveObject::reactivateAndComplete(void) + ?defaultConnection@QSymbianSocketManager@@QBEPAVRConnection@@XZ @ 4612 NONAME ; class RConnection * QSymbianSocketManager::defaultConnection(void) const + ?qt_symbianGetSocketServer@@YAAAVRSocketServ@@XZ @ 4613 NONAME ; class RSocketServ & qt_symbianGetSocketServer(void) + ?maybeQueueForLater@QActiveObject@@QAE_NXZ @ 4614 NONAME ; bool QActiveObject::maybeQueueForLater(void) + ??_EQActiveObject@@UAE@I@Z @ 4615 NONAME ; QActiveObject::~QActiveObject(unsigned int) + ?lookupSocket@QSymbianSocketManager@@QBE_NHAAVRSocket@@@Z @ 4616 NONAME ; bool QSymbianSocketManager::lookupSocket(int, class RSocket &) const + ?wait@QActiveObject@@SA_NPAVCActive@@H@Z @ 4617 NONAME ; bool QActiveObject::wait(class CActive *, int) + ?instance@QSymbianSocketManager@@SAAAV1@XZ @ 4618 NONAME ; class QSymbianSocketManager & QSymbianSocketManager::instance(void) + ??0QSymbianSocketManager@@QAE@XZ @ 4619 NONAME ; QSymbianSocketManager::QSymbianSocketManager(void) + ?create@QNonContiguousByteDeviceFactory@@SAPAVQNonContiguousByteDevice@@V?$QSharedPointer@VQRingBuffer@@@@@Z @ 4620 NONAME ; class QNonContiguousByteDevice * QNonContiguousByteDeviceFactory::create(class QSharedPointer) + ??1QSymbianSocketManager@@QAE@XZ @ 4621 NONAME ; QSymbianSocketManager::~QSymbianSocketManager(void) + ?isResetDisabled@QNonContiguousByteDevice@@QAE_NXZ @ 4622 NONAME ; bool QNonContiguousByteDevice::isResetDisabled(void) + ??1QActiveObject@@UAE@XZ @ 4623 NONAME ; QActiveObject::~QActiveObject(void) + ?wait@QActiveObject@@SA_NV?$QList@PAVCActive@@@@H@Z @ 4624 NONAME ; bool QActiveObject::wait(class QList, int) + ?maybeDeferSocketEvent@QActiveObject@@QAE_NXZ @ 4625 NONAME ; bool QActiveObject::maybeDeferSocketEvent(void) + ?lookupSocket@QSymbianSocketManager@@QBEHABVRSocket@@@Z @ 4626 NONAME ; int QSymbianSocketManager::lookupSocket(class RSocket const &) const + ?areSocketEventsBlocked@QEventDispatcherSymbian@@QBE_NXZ @ 4627 NONAME ; bool QEventDispatcherSymbian::areSocketEventsBlocked(void) const + ?addDeferredSocketActiveObject@QEventDispatcherSymbian@@QAEXPAVQActiveObject@@@Z @ 4628 NONAME ; void QEventDispatcherSymbian::addDeferredSocketActiveObject(class QActiveObject *) + ?getSocketServer@QSymbianSocketManager@@QAEAAVRSocketServ@@XZ @ 4629 NONAME ; class RSocketServ & QSymbianSocketManager::getSocketServer(void) + ?removeSocket@QSymbianSocketManager@@QAE_NABVRSocket@@@Z @ 4630 NONAME ; bool QSymbianSocketManager::removeSocket(class RSocket const &) diff --git a/src/s60installs/bwins/QtGuiu.def b/src/s60installs/bwins/QtGuiu.def index 9b4c0f7..f711475 100644 --- a/src/s60installs/bwins/QtGuiu.def +++ b/src/s60installs/bwins/QtGuiu.def @@ -13149,3 +13149,29 @@ EXPORTS ?ProcessCommandParametersL@QS60MainAppUi@@UAEHW4TApaCommand@@AAV?$TBuf@$0BAA@@@ABVTDesC8@@@Z @ 13148 NONAME ; int QS60MainAppUi::ProcessCommandParametersL(enum TApaCommand, class TBuf<256> &, class TDesC8 const &) ?openFile@QFileOpenEvent@@QBE_NAAVQFile@@V?$QFlags@W4OpenModeFlag@QIODevice@@@@@Z @ 13149 NONAME ; bool QFileOpenEvent::openFile(class QFile &, class QFlags) const ??0QFileOpenEvent@@QAE@ABVRFile@@@Z @ 13150 NONAME ; QFileOpenEvent::QFileOpenEvent(class RFile const &) + ?tr@QInternalMimeData@@SA?AVQString@@PBD0H@Z @ 13151 NONAME ; class QString QInternalMimeData::tr(char const *, char const *, int) + ?assignedInputContext@QWidgetPrivate@@QBEPAVQInputContext@@XZ @ 13152 NONAME ; class QInputContext * QWidgetPrivate::assignedInputContext(void) const + ?formatsHelper@QInternalMimeData@@SA?AVQStringList@@PBVQMimeData@@@Z @ 13153 NONAME ; class QStringList QInternalMimeData::formatsHelper(class QMimeData const *) + ??_EQInternalMimeData@@UAE@I@Z @ 13154 NONAME ; QInternalMimeData::~QInternalMimeData(unsigned int) + ?hasFormatHelper@QInternalMimeData@@SA_NABVQString@@PBVQMimeData@@@Z @ 13155 NONAME ; bool QInternalMimeData::hasFormatHelper(class QString const &, class QMimeData const *) + ?renderDataHelper@QInternalMimeData@@SA?AVQByteArray@@ABVQString@@PBVQMimeData@@@Z @ 13156 NONAME ; class QByteArray QInternalMimeData::renderDataHelper(class QString const &, class QMimeData const *) + ?setLineHeight@QTextBlockFormat@@QAEXMH@Z @ 13157 NONAME ; void QTextBlockFormat::setLineHeight(float, int) + ?trUtf8@QInternalMimeData@@SA?AVQString@@PBD0H@Z @ 13158 NONAME ; class QString QInternalMimeData::trUtf8(char const *, char const *, int) + ?staticMetaObject@QInternalMimeData@@2UQMetaObject@@B @ 13159 NONAME ; struct QMetaObject const QInternalMimeData::staticMetaObject + ?lineHeight@QTextBlockFormat@@QBEMMM@Z @ 13160 NONAME ; float QTextBlockFormat::lineHeight(float, float) const + ?qt_metacast@QInternalMimeData@@UAEPAXPBD@Z @ 13161 NONAME ; void * QInternalMimeData::qt_metacast(char const *) + ?lineHeightType@QTextBlockFormat@@QBEHXZ @ 13162 NONAME ; int QTextBlockFormat::lineHeightType(void) const + ?qt_metacall@QInternalMimeData@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 13163 NONAME ; int QInternalMimeData::qt_metacall(enum QMetaObject::Call, int, void * *) + ?getStaticMetaObject@QInternalMimeData@@SAABUQMetaObject@@XZ @ 13164 NONAME ; struct QMetaObject const & QInternalMimeData::getStaticMetaObject(void) + ??0QInternalMimeData@@QAE@XZ @ 13165 NONAME ; QInternalMimeData::QInternalMimeData(void) + ?updateMicroFocus@QLineControl@@IAEXXZ @ 13166 NONAME ; void QLineControl::updateMicroFocus(void) + ?formats@QInternalMimeData@@UBE?AVQStringList@@XZ @ 13167 NONAME ; class QStringList QInternalMimeData::formats(void) const + ?lineHeight@QTextBlockFormat@@QBEMXZ @ 13168 NONAME ; float QTextBlockFormat::lineHeight(void) const + ?trUtf8@QInternalMimeData@@SA?AVQString@@PBD0@Z @ 13169 NONAME ; class QString QInternalMimeData::trUtf8(char const *, char const *) + ??1QInternalMimeData@@UAE@XZ @ 13170 NONAME ; QInternalMimeData::~QInternalMimeData(void) + ?hasFormat@QInternalMimeData@@UBE_NABVQString@@@Z @ 13171 NONAME ; bool QInternalMimeData::hasFormat(class QString const &) const + ?canReadData@QInternalMimeData@@SA_NABVQString@@@Z @ 13172 NONAME ; bool QInternalMimeData::canReadData(class QString const &) + ?tr@QInternalMimeData@@SA?AVQString@@PBD0@Z @ 13173 NONAME ; class QString QInternalMimeData::tr(char const *, char const *) + ?metaObject@QInternalMimeData@@UBEPBUQMetaObject@@XZ @ 13174 NONAME ; struct QMetaObject const * QInternalMimeData::metaObject(void) const + ?retrieveData@QInternalMimeData@@MBE?AVQVariant@@ABVQString@@W4Type@2@@Z @ 13175 NONAME ; class QVariant QInternalMimeData::retrieveData(class QString const &, enum QVariant::Type) const + diff --git a/src/s60installs/bwins/QtNetworku.def b/src/s60installs/bwins/QtNetworku.def index b01324c..3f8f6d2 100644 --- a/src/s60installs/bwins/QtNetworku.def +++ b/src/s60installs/bwins/QtNetworku.def @@ -1159,4 +1159,9 @@ EXPORTS ?engines@QNetworkConfigurationManagerPrivate@@QBE?AV?$QList@PAVQBearerEngine@@@@XZ @ 1158 NONAME ; class QList QNetworkConfigurationManagerPrivate::engines(void) const ?isOnline@QNetworkConfigurationManagerPrivate@@QBE_NXZ @ 1159 NONAME ; bool QNetworkConfigurationManagerPrivate::isOnline(void) const ?startPolling@QNetworkConfigurationManagerPrivate@@AAEXXZ @ 1160 NONAME ; void QNetworkConfigurationManagerPrivate::startPolling(void) + ?peerVerifyName@QSslSocket@@QBE?AVQString@@XZ @ 1161 NONAME ; class QString QSslSocket::peerVerifyName(void) const + ?setPeerVerifyName@QSslSocket@@QAEXABVQString@@@Z @ 1162 NONAME ; void QSslSocket::setPeerVerifyName(class QString const &) + ?nativeSession@QNetworkSessionPrivate@@SAPAVRConnection@@AAVQNetworkSession@@@Z @ 1163 NONAME ; class RConnection * QNetworkSessionPrivate::nativeSession(class QNetworkSession &) + ?nativeOpenSocket@QNetworkSessionPrivate@@SAHAAVQNetworkSession@@AAVRSocket@@III@Z @ 1164 NONAME ; int QNetworkSessionPrivate::nativeOpenSocket(class QNetworkSession &, class RSocket &, unsigned int, unsigned int, unsigned int) + ?nativeOpenHostResolver@QNetworkSessionPrivate@@SAHAAVQNetworkSession@@AAVRHostResolver@@II@Z @ 1165 NONAME ; int QNetworkSessionPrivate::nativeOpenHostResolver(class QNetworkSession &, class RHostResolver &, unsigned int, unsigned int) diff --git a/src/s60installs/bwins/QtTestu.def b/src/s60installs/bwins/QtTestu.def index a7bb9cd..239eb1f 100644 --- a/src/s60installs/bwins/QtTestu.def +++ b/src/s60installs/bwins/QtTestu.def @@ -77,4 +77,93 @@ EXPORTS ?staticMetaObject@QTestEventLoop@@2UQMetaObject@@B @ 76 NONAME ; struct QMetaObject const QTestEventLoop::staticMetaObject ?setBenchmarkResult@QTest@@YAXMW4QBenchmarkMetric@1@@Z @ 77 NONAME ; void QTest::setBenchmarkResult(float, enum QTest::QBenchmarkMetric) ?endBenchmarkMeasurement@QTest@@YA_KXZ @ 78 NONAME ; unsigned long long QTest::endBenchmarkMeasurement(void) + ?addXFail@QTestLog@@SAXPBD0H@Z @ 79 NONAME ; void QTestLog::addXFail(char const *, char const *, int) + ?leaveTestFunction@QTestLog@@SAXXZ @ 80 NONAME ; void QTestLog::leaveTestFunction(void) + ?setCurrentTestFunction@QTestResult@@SAXPBD@Z @ 81 NONAME ; void QTestResult::setCurrentTestFunction(char const *) + ?currentTestObjectName@QTestResult@@SAPBDXZ @ 82 NONAME ; char const * QTestResult::currentTestObjectName(void) + ?allDataPassed@QTestResult@@SA_NXZ @ 83 NONAME ; bool QTestResult::allDataPassed(void) + ?redirectOutput@QTestLog@@SAXPBD@Z @ 84 NONAME ; void QTestLog::redirectOutput(char const *) + ?testData@QTestTable@@QBEPAVQTestData@@H@Z @ 85 NONAME ; class QTestData * QTestTable::testData(int) const + ?isEmpty@QTestTable@@QBE_NXZ @ 86 NONAME ; bool QTestTable::isEmpty(void) const + ?logMode@QTestLog@@SA?AW4LogMode@1@XZ @ 87 NONAME ; enum QTestLog::LogMode QTestLog::logMode(void) + ?dataCount@QTestTable@@QBEHXZ @ 88 NONAME ; int QTestTable::dataCount(void) const + ?addFailure@QTestResult@@SAXPBD0H@Z @ 89 NONAME ; void QTestResult::addFailure(char const *, char const *, int) + ?setCurrentTestData@QTestResult@@SAXPAVQTestData@@@Z @ 90 NONAME ; void QTestResult::setCurrentTestData(class QTestData *) + ?setMode@QBenchmarkGlobalData@@QAEXW4Mode@1@@Z @ 91 NONAME ; void QBenchmarkGlobalData::setMode(enum QBenchmarkGlobalData::Mode) + ??1QTestTable@@QAE@XZ @ 92 NONAME ; QTestTable::~QTestTable(void) + ?setLogMode@QTestLog@@SAXW4LogMode@1@@Z @ 93 NONAME ; void QTestLog::setLogMode(enum QTestLog::LogMode) + ?addBenchmarkResult@QTestLog@@SAXABVQBenchmarkResult@@@Z @ 94 NONAME ; void QTestLog::addBenchmarkResult(class QBenchmarkResult const &) + ?setVerboseLevel@QTestLog@@SAXH@Z @ 95 NONAME ; void QTestLog::setVerboseLevel(int) + ??0QBenchmarkGlobalData@@QAE@XZ @ 96 NONAME ; QBenchmarkGlobalData::QBenchmarkGlobalData(void) + ?stopLogging@QTestLog@@SAXXZ @ 97 NONAME ; void QTestLog::stopLogging(void) + ?setCurrentGlobalTestData@QTestResult@@SAXPAVQTestData@@@Z @ 98 NONAME ; void QTestResult::setCurrentGlobalTestData(class QTestData *) + ?currentTestLocation@QTestResult@@SA?AW4TestLocation@1@XZ @ 99 NONAME ; enum QTestResult::TestLocation QTestResult::currentTestLocation(void) + ?currentTestFunction@QTestResult@@SAPBDXZ @ 100 NONAME ; char const * QTestResult::currentTestFunction(void) + ?dataTag@QTestTable@@QBEPBDH@Z @ 101 NONAME ; char const * QTestTable::dataTag(int) const + ?expectFail@QTestResult@@SA_NPBD0W4TestFailMode@QTest@@0H@Z @ 102 NONAME ; bool QTestResult::expectFail(char const *, char const *, enum QTest::TestFailMode, char const *, int) + ?currentDataTag@QTestResult@@SAPBDXZ @ 103 NONAME ; char const * QTestResult::currentDataTag(void) + ??0QTestTable@@QAE@XZ @ 104 NONAME ; QTestTable::QTestTable(void) + ?setFlushMode@QTestLog@@SAXW4FlushMode@1@@Z @ 105 NONAME ; void QTestLog::setFlushMode(enum QTestLog::FlushMode) + ?setCurrentTestObject@QTestResult@@SAXPBD@Z @ 106 NONAME ; void QTestResult::setCurrentTestObject(char const *) + ?beginDataRun@QBenchmarkTestMethodData@@QAEXXZ @ 107 NONAME ; void QBenchmarkTestMethodData::beginDataRun(void) + ?qtest_qParseArgs@QTest@@YAXHQAPAD_N@Z @ 108 NONAME ; void QTest::qtest_qParseArgs(int, char * * const, bool) + ?enterTestFunction@QTestLog@@SAXPBD@Z @ 109 NONAME ; void QTestLog::enterTestFunction(char const *) + ?clearGlobalTestTable@QTestTable@@SAXXZ @ 110 NONAME ; void QTestTable::clearGlobalTestTable(void) + ?addPass@QTestLog@@SAXPBD@Z @ 111 NONAME ; void QTestLog::addPass(char const *) + ?printUnhandledIgnoreMessages@QTestLog@@SAXXZ @ 112 NONAME ; void QTestLog::printUnhandledIgnoreMessages(void) + ?addColumn@QTestTable@@QAEXHPBD@Z @ 113 NONAME ; void QTestTable::addColumn(int, char const *) + ?setSkipCurrentTest@QTestResult@@SAX_N@Z @ 114 NONAME ; void QTestResult::setSkipCurrentTest(bool) + ?currentTestFailed@QTestResult@@SA_NXZ @ 115 NONAME ; bool QTestResult::currentTestFailed(void) + ?createMeasurer@QBenchmarkGlobalData@@QAEPAVQBenchmarkMeasurerBase@@XZ @ 116 NONAME ; class QBenchmarkMeasurerBase * QBenchmarkGlobalData::createMeasurer(void) + ?startLogging@QTestLog@@SAXXZ @ 117 NONAME ; void QTestLog::startLogging(void) + ?printAvailableFunctions@QTest@@3_NA @ 118 NONAME ; bool QTest::printAvailableFunctions + ?testFailed@QTestResult@@SA_NXZ @ 119 NONAME ; bool QTestResult::testFailed(void) + ?current@QBenchmarkTestMethodData@@2PAV1@A @ 120 NONAME ; class QBenchmarkTestMethodData * QBenchmarkTestMethodData::current + ?currentGlobalDataTag@QTestResult@@SAPBDXZ @ 121 NONAME ; char const * QTestResult::currentGlobalDataTag(void) + ?adjustIterationCount@QBenchmarkTestMethodData@@QAEHH@Z @ 122 NONAME ; int QBenchmarkTestMethodData::adjustIterationCount(int) + ?current@QBenchmarkGlobalData@@2PAV1@A @ 123 NONAME ; class QBenchmarkGlobalData * QBenchmarkGlobalData::current + ?warn@QTestLog@@SAXPBD@Z @ 124 NONAME ; void QTestLog::warn(char const *) + ?testFunctions@QTest@@3VQStringList@@A @ 125 NONAME ; class QStringList QTest::testFunctions + ?elementTypeId@QTestTable@@QBEHH@Z @ 126 NONAME ; int QTestTable::elementTypeId(int) const + ?ignoreMessage@QTestResult@@SAXW4QtMsgType@@PBD@Z @ 127 NONAME ; void QTestResult::ignoreMessage(enum QtMsgType, char const *) + ?globalTestTable@QTestTable@@SAPAV1@XZ @ 128 NONAME ; class QTestTable * QTestTable::globalTestTable(void) + ??0QBenchmarkTestMethodData@@QAE@XZ @ 129 NONAME ; QBenchmarkTestMethodData::QBenchmarkTestMethodData(void) + ?currentTestTable@QTestTable@@SAPAV1@XZ @ 130 NONAME ; class QTestTable * QTestTable::currentTestTable(void) + ?addFail@QTestLog@@SAXPBD0H@Z @ 131 NONAME ; void QTestLog::addFail(char const *, char const *, int) + ?endDataRun@QBenchmarkTestMethodData@@QAEXXZ @ 132 NONAME ; void QBenchmarkTestMethodData::endDataRun(void) + ?resultsAccepted@QBenchmarkTestMethodData@@QBE_NXZ @ 133 NONAME ; bool QBenchmarkTestMethodData::resultsAccepted(void) const + ?verify@QTestResult@@SA_N_NPBD11H@Z @ 134 NONAME ; bool QTestResult::verify(bool, char const *, char const *, char const *, int) + ??1QBenchmarkTestMethodData@@QAE@XZ @ 135 NONAME ; QBenchmarkTestMethodData::~QBenchmarkTestMethodData(void) + ?addIgnoreMessage@QTestLog@@SAXW4QtMsgType@@PBD@Z @ 136 NONAME ; void QTestLog::addIgnoreMessage(enum QtMsgType, char const *) + ?newData@QTestTable@@QAEPAVQTestData@@PBD@Z @ 137 NONAME ; class QTestData * QTestTable::newData(char const *) + ?reset@QTestResult@@SAXXZ @ 138 NONAME ; void QTestResult::reset(void) + ?currentTestData@QTestResult@@SAPAVQTestData@@XZ @ 139 NONAME ; class QTestData * QTestResult::currentTestData(void) + ?skipCurrentTest@QTestResult@@SA_NXZ @ 140 NONAME ; bool QTestResult::skipCurrentTest(void) + ?outputFileName@QTestLog@@SAPBDXZ @ 141 NONAME ; char const * QTestLog::outputFileName(void) + ?adjustMedianIterationCount@QBenchmarkGlobalData@@QAEHXZ @ 142 NONAME ; int QBenchmarkGlobalData::adjustMedianIterationCount(void) + ??0QTestLog@@AAE@XZ @ 143 NONAME ; QTestLog::QTestLog(void) + ?compare@QTestResult@@SA_N_NPBDPAD2111H@Z @ 144 NONAME ; bool QTestResult::compare(bool, char const *, char *, char *, char const *, char const *, char const *, int) + ?elementCount@QTestTable@@QBEHXZ @ 145 NONAME ; int QTestTable::elementCount(void) const + ?setResult@QBenchmarkTestMethodData@@QAEXMW4QBenchmarkMetric@QTest@@_N@Z @ 146 NONAME ; void QBenchmarkTestMethodData::setResult(float, enum QTest::QBenchmarkMetric, bool) + ?finishedCurrentTestFunction@QTestResult@@SAXXZ @ 147 NONAME ; void QTestResult::finishedCurrentTestFunction(void) + ?setCurrentTestLocation@QTestResult@@SAXW4TestLocation@1@@Z @ 148 NONAME ; void QTestResult::setCurrentTestLocation(enum QTestResult::TestLocation) + ?currentGlobalTestData@QTestResult@@SAPAVQTestData@@XZ @ 149 NONAME ; class QTestData * QTestResult::currentGlobalTestData(void) + ?mode@QBenchmarkGlobalData@@QBE?AW4Mode@1@XZ @ 150 NONAME ; enum QBenchmarkGlobalData::Mode QBenchmarkGlobalData::mode(void) const + ?setMaxWarnings@QTestLog@@SAXH@Z @ 151 NONAME ; void QTestLog::setMaxWarnings(int) + ?failCount@QTestResult@@SAHXZ @ 152 NONAME ; int QTestResult::failCount(void) + ?verboseLevel@QTestLog@@SAHXZ @ 153 NONAME ; int QTestLog::verboseLevel(void) + ?passCount@QTestResult@@SAHXZ @ 154 NONAME ; int QTestResult::passCount(void) + ?indexOf@QTestTable@@QBEHPBD@Z @ 155 NONAME ; int QTestTable::indexOf(char const *) const + ?compare@QTestResult@@SA_N_NPBD1H@Z @ 156 NONAME ; bool QTestResult::compare(bool, char const *, char const *, int) + ?startLogging@QTestLog@@SAXI@Z @ 157 NONAME ; void QTestLog::startLogging(unsigned int) + ?addSkip@QTestLog@@SAXPBDW4SkipMode@QTest@@0H@Z @ 158 NONAME ; void QTestLog::addSkip(char const *, enum QTest::SkipMode, char const *, int) + ?testTags@QTest@@3VQStringList@@A @ 159 NONAME ; class QStringList QTest::testTags + ??1QTestLog@@AAE@XZ @ 160 NONAME ; QTestLog::~QTestLog(void) + ?unhandledIgnoreMessages@QTestLog@@SAHXZ @ 161 NONAME ; int QTestLog::unhandledIgnoreMessages(void) + ?info@QTestLog@@SAXPBD0H@Z @ 162 NONAME ; void QTestLog::info(char const *, char const *, int) + ??1QBenchmarkGlobalData@@QAE@XZ @ 163 NONAME ; QBenchmarkGlobalData::~QBenchmarkGlobalData(void) + ?isBenchmark@QBenchmarkTestMethodData@@QBE_NXZ @ 164 NONAME ; bool QBenchmarkTestMethodData::isBenchmark(void) const + ?addSkip@QTestResult@@SAXPBDW4SkipMode@QTest@@0H@Z @ 165 NONAME ; void QTestResult::addSkip(char const *, enum QTest::SkipMode, char const *, int) + ?skipCount@QTestResult@@SAHXZ @ 166 NONAME ; int QTestResult::skipCount(void) + ?addXPass@QTestLog@@SAXPBD0H@Z @ 167 NONAME ; void QTestLog::addXPass(char const *, char const *, int) diff --git a/src/s60installs/eabi/QtCoreu.def b/src/s60installs/eabi/QtCoreu.def index 207447f..c514fbd 100644 --- a/src/s60installs/eabi/QtCoreu.def +++ b/src/s60installs/eabi/QtCoreu.def @@ -1282,7 +1282,7 @@ EXPORTS _ZN23QEventDispatcherSymbian10startingUpEv @ 1281 NONAME _ZN23QEventDispatcherSymbian10timerFiredEi @ 1282 NONAME _ZN23QEventDispatcherSymbian11closingDownEv @ 1283 NONAME - _ZN23QEventDispatcherSymbian11socketFiredEP19QSocketActiveObject @ 1284 NONAME + _ZN23QEventDispatcherSymbian11socketFiredEP19QSocketActiveObject @ 1284 NONAME ABSENT _ZN23QEventDispatcherSymbian13processEventsE6QFlagsIN10QEventLoop17ProcessEventsFlagEE @ 1285 NONAME _ZN23QEventDispatcherSymbian13registerTimerEiiP7QObject @ 1286 NONAME _ZN23QEventDispatcherSymbian15unregisterTimerEi @ 1287 NONAME @@ -1439,7 +1439,7 @@ EXPORTS _ZN31QAbstractEventDispatcherPrivate4initEv @ 1438 NONAME _ZN31QNonContiguousByteDeviceFactory4wrapEP24QNonContiguousByteDevice @ 1439 NONAME _ZN31QNonContiguousByteDeviceFactory6createEP10QByteArray @ 1440 NONAME - _ZN31QNonContiguousByteDeviceFactory6createEP11QRingBuffer @ 1441 NONAME + _ZN31QNonContiguousByteDeviceFactory6createEP11QRingBuffer @ 1441 NONAME ABSENT _ZN31QNonContiguousByteDeviceFactory6createEP9QIODevice @ 1442 NONAME _ZN4QDir10setCurrentERK7QString @ 1443 NONAME _ZN4QDir10setSortingE6QFlagsINS_8SortFlagEE @ 1444 NONAME @@ -3806,4 +3806,30 @@ EXPORTS _ZNK13QElapsedTimer12nsecsElapsedEv @ 3805 NONAME _ZNK11QMetaMethod8revisionEv @ 3806 NONAME _ZNK13QMetaProperty8revisionEv @ 3807 NONAME + _Z25qt_symbianGetSocketServerv @ 3808 NONAME + _ZN13QActiveObject18maybeQueueForLaterEv @ 3809 NONAME + _ZN13QActiveObject21maybeDeferSocketEventEv @ 3810 NONAME + _ZN13QActiveObject21reactivateAndCompleteEv @ 3811 NONAME + _ZN13QActiveObject4waitE5QListIP7CActiveEi @ 3812 NONAME + _ZN13QActiveObject4waitEP7CActivei @ 3813 NONAME + _ZN13QActiveObjectC2EiP23QEventDispatcherSymbian @ 3814 NONAME + _ZN13QActiveObjectD0Ev @ 3815 NONAME + _ZN13QActiveObjectD1Ev @ 3816 NONAME + _ZN13QActiveObjectD2Ev @ 3817 NONAME + _ZN21QSymbianSocketManager12removeSocketERK7RSocket @ 3818 NONAME + _ZN21QSymbianSocketManager15getSocketServerEv @ 3819 NONAME + _ZN21QSymbianSocketManager20setDefaultConnectionEP11RConnection @ 3820 NONAME + _ZN21QSymbianSocketManager8instanceEv @ 3821 NONAME + _ZN21QSymbianSocketManager9addSocketERK7RSocket @ 3822 NONAME + _ZN21QSymbianSocketManagerC1Ev @ 3823 NONAME + _ZN21QSymbianSocketManagerC2Ev @ 3824 NONAME + _ZN21QSymbianSocketManagerD1Ev @ 3825 NONAME + _ZN21QSymbianSocketManagerD2Ev @ 3826 NONAME + _ZN31QNonContiguousByteDeviceFactory6createE14QSharedPointerI11QRingBufferE @ 3827 NONAME + _ZNK21QSymbianSocketManager12lookupSocketERK7RSocket @ 3828 NONAME + _ZNK21QSymbianSocketManager12lookupSocketEiR7RSocket @ 3829 NONAME + _ZNK21QSymbianSocketManager17defaultConnectionEv @ 3830 NONAME + _ZTI13QActiveObject @ 3831 NONAME + _ZTV13QActiveObject @ 3832 NONAME + gzungetc @ 3833 NONAME diff --git a/src/s60installs/eabi/QtGuiu.def b/src/s60installs/eabi/QtGuiu.def index 722dee8..c28bfb5 100644 --- a/src/s60installs/eabi/QtGuiu.def +++ b/src/s60installs/eabi/QtGuiu.def @@ -12337,4 +12337,24 @@ EXPORTS _ZN12QTextControl23setWordSelectionEnabledEb @ 12336 NONAME _ZNK12QTextControl13isDragEnabledEv @ 12337 NONAME _ZNK12QTextControl22isWordSelectionEnabledEv @ 12338 NONAME + _ZN12QLineControl16updateMicroFocusEv @ 12339 NONAME + _ZN17QInternalMimeData11canReadDataERK7QString @ 12340 NONAME + _ZN17QInternalMimeData11qt_metacallEN11QMetaObject4CallEiPPv @ 12341 NONAME + _ZN17QInternalMimeData11qt_metacastEPKc @ 12342 NONAME + _ZN17QInternalMimeData13formatsHelperEPK9QMimeData @ 12343 NONAME + _ZN17QInternalMimeData15hasFormatHelperERK7QStringPK9QMimeData @ 12344 NONAME + _ZN17QInternalMimeData16renderDataHelperERK7QStringPK9QMimeData @ 12345 NONAME + _ZN17QInternalMimeData16staticMetaObjectE @ 12346 NONAME DATA 16 + _ZN17QInternalMimeData19getStaticMetaObjectEv @ 12347 NONAME + _ZN17QInternalMimeDataC2Ev @ 12348 NONAME + _ZN17QInternalMimeDataD0Ev @ 12349 NONAME + _ZN17QInternalMimeDataD1Ev @ 12350 NONAME + _ZN17QInternalMimeDataD2Ev @ 12351 NONAME + _ZNK14QWidgetPrivate20assignedInputContextEv @ 12352 NONAME + _ZNK17QInternalMimeData10metaObjectEv @ 12353 NONAME + _ZNK17QInternalMimeData12retrieveDataERK7QStringN8QVariant4TypeE @ 12354 NONAME + _ZNK17QInternalMimeData7formatsEv @ 12355 NONAME + _ZNK17QInternalMimeData9hasFormatERK7QString @ 12356 NONAME + _ZTI17QInternalMimeData @ 12357 NONAME + _ZTV17QInternalMimeData @ 12358 NONAME diff --git a/src/s60installs/eabi/QtNetworku.def b/src/s60installs/eabi/QtNetworku.def index 9b989a7..672ae84 100644 --- a/src/s60installs/eabi/QtNetworku.def +++ b/src/s60installs/eabi/QtNetworku.def @@ -1181,4 +1181,9 @@ EXPORTS _ZNK35QNetworkConfigurationManagerPrivate27configurationFromIdentifierERK7QString @ 1180 NONAME _ZNK35QNetworkConfigurationManagerPrivate7enginesEv @ 1181 NONAME _ZNK35QNetworkConfigurationManagerPrivate8isOnlineEv @ 1182 NONAME + _ZN10QSslSocket17setPeerVerifyNameERK7QString @ 1183 NONAME + _ZN22QNetworkSessionPrivate13nativeSessionER15QNetworkSession @ 1184 NONAME + _ZN22QNetworkSessionPrivate16nativeOpenSocketER15QNetworkSessionR7RSocketjjj @ 1185 NONAME + _ZN22QNetworkSessionPrivate22nativeOpenHostResolverER15QNetworkSessionR13RHostResolverjj @ 1186 NONAME + _ZNK10QSslSocket14peerVerifyNameEv @ 1187 NONAME diff --git a/src/s60installs/eabi/QtTestu.def b/src/s60installs/eabi/QtTestu.def index 5cb95ba..370466b 100644 --- a/src/s60installs/eabi/QtTestu.def +++ b/src/s60installs/eabi/QtTestu.def @@ -70,4 +70,98 @@ EXPORTS _ZTI14QTestEventLoop @ 69 NONAME _ZTV14QTestEventLoop @ 70 NONAME _ZN5QTest18setBenchmarkResultEfNS_16QBenchmarkMetricE @ 71 NONAME + _ZN10QTestTable15globalTestTableEv @ 72 NONAME + _ZN10QTestTable16currentTestTableEv @ 73 NONAME + _ZN10QTestTable20clearGlobalTestTableEv @ 74 NONAME + _ZN10QTestTable7newDataEPKc @ 75 NONAME + _ZN10QTestTable9addColumnEiPKc @ 76 NONAME + _ZN10QTestTableC1Ev @ 77 NONAME + _ZN10QTestTableC2Ev @ 78 NONAME + _ZN10QTestTableD1Ev @ 79 NONAME + _ZN10QTestTableD2Ev @ 80 NONAME + _ZN11QTestResult10addFailureEPKcS1_i @ 81 NONAME + _ZN11QTestResult10expectFailEPKcS1_N5QTest12TestFailModeES1_i @ 82 NONAME + _ZN11QTestResult10testFailedEv @ 83 NONAME + _ZN11QTestResult13allDataPassedEv @ 84 NONAME + _ZN11QTestResult13ignoreMessageE9QtMsgTypePKc @ 85 NONAME + _ZN11QTestResult14currentDataTagEv @ 86 NONAME + _ZN11QTestResult15currentTestDataEv @ 87 NONAME + _ZN11QTestResult15skipCurrentTestEv @ 88 NONAME + _ZN11QTestResult17currentTestFailedEv @ 89 NONAME + _ZN11QTestResult18setCurrentTestDataEP9QTestData @ 90 NONAME + _ZN11QTestResult18setSkipCurrentTestEb @ 91 NONAME + _ZN11QTestResult19currentTestFunctionEv @ 92 NONAME + _ZN11QTestResult19currentTestLocationEv @ 93 NONAME + _ZN11QTestResult20currentGlobalDataTagEv @ 94 NONAME + _ZN11QTestResult20setCurrentTestObjectEPKc @ 95 NONAME + _ZN11QTestResult21currentGlobalTestDataEv @ 96 NONAME + _ZN11QTestResult21currentTestObjectNameEv @ 97 NONAME + _ZN11QTestResult22setCurrentTestFunctionEPKc @ 98 NONAME + _ZN11QTestResult22setCurrentTestLocationENS_12TestLocationE @ 99 NONAME + _ZN11QTestResult24setCurrentGlobalTestDataEP9QTestData @ 100 NONAME + _ZN11QTestResult27finishedCurrentTestFunctionEv @ 101 NONAME + _ZN11QTestResult5resetEv @ 102 NONAME + _ZN11QTestResult6verifyEbPKcS1_S1_i @ 103 NONAME + _ZN11QTestResult7addSkipEPKcN5QTest8SkipModeES1_i @ 104 NONAME + _ZN11QTestResult7compareEbPKcPcS2_S1_S1_S1_i @ 105 NONAME + _ZN11QTestResult7compareEbPKcS1_i @ 106 NONAME + _ZN11QTestResult9failCountEv @ 107 NONAME + _ZN11QTestResult9passCountEv @ 108 NONAME + _ZN11QTestResult9skipCountEv @ 109 NONAME + _ZN20QBenchmarkGlobalData14createMeasurerEv @ 110 NONAME + _ZN20QBenchmarkGlobalData26adjustMedianIterationCountEv @ 111 NONAME + _ZN20QBenchmarkGlobalData7currentE @ 112 NONAME DATA 4 + _ZN20QBenchmarkGlobalData7setModeENS_4ModeE @ 113 NONAME + _ZN20QBenchmarkGlobalDataC1Ev @ 114 NONAME + _ZN20QBenchmarkGlobalDataC2Ev @ 115 NONAME + _ZN20QBenchmarkGlobalDataD1Ev @ 116 NONAME + _ZN20QBenchmarkGlobalDataD2Ev @ 117 NONAME + _ZN24QBenchmarkTestMethodData10endDataRunEv @ 118 NONAME + _ZN24QBenchmarkTestMethodData12beginDataRunEv @ 119 NONAME + _ZN24QBenchmarkTestMethodData20adjustIterationCountEi @ 120 NONAME + _ZN24QBenchmarkTestMethodData7currentE @ 121 NONAME DATA 4 + _ZN24QBenchmarkTestMethodData9setResultEfN5QTest16QBenchmarkMetricEb @ 122 NONAME + _ZN24QBenchmarkTestMethodDataC1Ev @ 123 NONAME + _ZN24QBenchmarkTestMethodDataC2Ev @ 124 NONAME + _ZN24QBenchmarkTestMethodDataD1Ev @ 125 NONAME + _ZN24QBenchmarkTestMethodDataD2Ev @ 126 NONAME + _ZN5QTest13testFunctionsE @ 127 NONAME DATA 4 + _ZN5QTest16qtest_qParseArgsEiPPcb @ 128 NONAME + _ZN5QTest23printAvailableFunctionsE @ 129 NONAME DATA 1 + _ZN5QTest8testTagsE @ 130 NONAME DATA 4 + _ZN8QTestLog10setLogModeENS_7LogModeE @ 131 NONAME + _ZN8QTestLog11stopLoggingEv @ 132 NONAME + _ZN8QTestLog12setFlushModeENS_9FlushModeE @ 133 NONAME + _ZN8QTestLog12startLoggingEj @ 134 NONAME + _ZN8QTestLog12startLoggingEv @ 135 NONAME + _ZN8QTestLog12verboseLevelEv @ 136 NONAME + _ZN8QTestLog14outputFileNameEv @ 137 NONAME + _ZN8QTestLog14redirectOutputEPKc @ 138 NONAME + _ZN8QTestLog14setMaxWarningsEi @ 139 NONAME + _ZN8QTestLog15setVerboseLevelEi @ 140 NONAME + _ZN8QTestLog16addIgnoreMessageE9QtMsgTypePKc @ 141 NONAME + _ZN8QTestLog17enterTestFunctionEPKc @ 142 NONAME + _ZN8QTestLog17leaveTestFunctionEv @ 143 NONAME + _ZN8QTestLog18addBenchmarkResultERK16QBenchmarkResult @ 144 NONAME + _ZN8QTestLog23unhandledIgnoreMessagesEv @ 145 NONAME + _ZN8QTestLog28printUnhandledIgnoreMessagesEv @ 146 NONAME + _ZN8QTestLog4infoEPKcS1_i @ 147 NONAME + _ZN8QTestLog4warnEPKc @ 148 NONAME + _ZN8QTestLog7addFailEPKcS1_i @ 149 NONAME + _ZN8QTestLog7addPassEPKc @ 150 NONAME + _ZN8QTestLog7addSkipEPKcN5QTest8SkipModeES1_i @ 151 NONAME + _ZN8QTestLog7logModeEv @ 152 NONAME + _ZN8QTestLog8addXFailEPKcS1_i @ 153 NONAME + _ZN8QTestLog8addXPassEPKcS1_i @ 154 NONAME + _ZN8QTestLogC1Ev @ 155 NONAME + _ZN8QTestLogC2Ev @ 156 NONAME + _ZN8QTestLogD1Ev @ 157 NONAME + _ZN8QTestLogD2Ev @ 158 NONAME + _ZNK10QTestTable12elementCountEv @ 159 NONAME + _ZNK10QTestTable13elementTypeIdEi @ 160 NONAME + _ZNK10QTestTable7dataTagEi @ 161 NONAME + _ZNK10QTestTable7indexOfEPKc @ 162 NONAME + _ZNK10QTestTable7isEmptyEv @ 163 NONAME + _ZNK10QTestTable8testDataEi @ 164 NONAME + _ZNK10QTestTable9dataCountEv @ 165 NONAME -- cgit v0.12 From 7d3832891e8229051d7ddc420cd0a323a4f5d17a Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Wed, 23 Mar 2011 16:09:31 +0100 Subject: tst_qnetworkreply: Use proper Content-Type Reviewed-by: Peter Hartmann --- tests/auto/qnetworkreply/tst_qnetworkreply.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp index f8a9530..a5f1577 100644 --- a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp @@ -1768,6 +1768,7 @@ void tst_QNetworkReply::postToHttp() QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi"); QNetworkRequest request(url); + request.setRawHeader("Content-Type", "application/octet-stream"); QNetworkReplyPtr reply; QFETCH(QByteArray, data); @@ -1794,6 +1795,7 @@ void tst_QNetworkReply::postToHttpSynchronous() QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi"); QNetworkRequest request(url); + request.setRawHeader("Content-Type", "application/octet-stream"); request.setAttribute( QNetworkRequest::SynchronousRequestAttribute, @@ -3408,6 +3410,8 @@ void tst_QNetworkReply::ioPostToHttpFromFile() QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi"); QNetworkRequest request(url); + request.setRawHeader("Content-Type", "application/octet-stream"); + QNetworkReplyPtr reply = manager.post(request, &sourceFile); connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); @@ -3484,8 +3488,10 @@ void tst_QNetworkReply::ioPostToHttpFromSocket() socketpair.endPoints[0]->write(data); QNetworkRequest request(url); + request.setRawHeader("Content-Type", "application/octet-stream"); + manager.setProxy(proxy); - QNetworkReplyPtr reply = manager.post(QNetworkRequest(url), socketpair.endPoints[1]); + QNetworkReplyPtr reply = manager.post(request, socketpair.endPoints[1]); socketpair.endPoints[0]->close(); connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); @@ -3558,6 +3564,7 @@ void tst_QNetworkReply::ioPostToHttpFromSocketSynchronous() QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/md5sum.cgi"); QNetworkRequest request(url); + request.setRawHeader("Content-Type", "application/octet-stream"); request.setAttribute( QNetworkRequest::SynchronousRequestAttribute, true); @@ -3587,7 +3594,8 @@ void tst_QNetworkReply::ioPostToHttpFromMiddleOfFileToEnd() QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi"; QNetworkRequest request(url); - QNetworkReplyPtr reply = manager.post(QNetworkRequest(url), &sourceFile); + request.setRawHeader("Content-Type", "application/octet-stream"); + QNetworkReplyPtr reply = manager.post(request, &sourceFile); connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); connect(&manager, SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)), @@ -3613,6 +3621,7 @@ void tst_QNetworkReply::ioPostToHttpFromMiddleOfFileFiveBytes() QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi"; QNetworkRequest request(url); + request.setRawHeader("Content-Type", "application/octet-stream"); // only send 5 bytes request.setHeader(QNetworkRequest::ContentLengthHeader, 5); QVERIFY(request.header(QNetworkRequest::ContentLengthHeader).isValid()); @@ -3673,6 +3682,7 @@ void tst_QNetworkReply::ioPostToHttpNoBufferFlag() QUrl url = "http://" + QtNetworkSettings::serverName() + "/qtest/protected/cgi-bin/md5sum.cgi"; QNetworkRequest request(url); + request.setRawHeader("Content-Type", "application/octet-stream"); // disallow buffering request.setAttribute(QNetworkRequest::DoNotBufferUploadDataAttribute, true); request.setHeader(QNetworkRequest::ContentLengthHeader, data.size()); @@ -3735,6 +3745,7 @@ void tst_QNetworkReply::ioPostToHttpsUploadProgress() // create the request QUrl url = QUrl(QString("https://127.0.0.1:%1/").arg(server.serverPort())); QNetworkRequest request(url); + request.setRawHeader("Content-Type", "application/octet-stream"); QNetworkReplyPtr reply = manager.post(request, &sourceFile); QSignalSpy spy(reply, SIGNAL(uploadProgress(qint64,qint64))); connect(&server, SIGNAL(newEncryptedConnection()), &QTestEventLoop::instance(), SLOT(exitLoop())); @@ -3956,6 +3967,7 @@ void tst_QNetworkReply::ioPostToHttpEmptyUploadProgress() // create the request QUrl url = QUrl(QString("http://127.0.0.1:%1/").arg(server.serverPort())); QNetworkRequest request(url); + request.setRawHeader("Content-Type", "application/octet-stream"); QNetworkReplyPtr reply = manager.post(request, &buffer); QSignalSpy spy(reply, SIGNAL(uploadProgress(qint64,qint64))); connect(&server, SIGNAL(newConnection()), &QTestEventLoop::instance(), SLOT(exitLoop())); @@ -4302,6 +4314,7 @@ void tst_QNetworkReply::receiveCookiesFromHttp() QByteArray data = cookieString.toLatin1() + '\n'; QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/set-cookie.cgi"); QNetworkRequest request(url); + request.setRawHeader("Content-Type", "application/octet-stream"); QNetworkReplyPtr reply; RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PostOperation, request, reply, data)); @@ -4329,7 +4342,7 @@ void tst_QNetworkReply::receiveCookiesFromHttpSynchronous() QUrl url("http://" + QtNetworkSettings::serverName() + "/qtest/cgi-bin/set-cookie.cgi"); QNetworkRequest request(url); - + request.setRawHeader("Content-Type", "application/octet-stream"); request.setAttribute( QNetworkRequest::SynchronousRequestAttribute, true); -- cgit v0.12 From 10d81f9a815f889ebf693f89eaf381299d7ccfc2 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Fri, 25 Mar 2011 10:30:17 +0100 Subject: QHostInfo: Don't mess with addr family ordering Reviewed-by: Aaron Tunney --- src/network/kernel/qhostinfo_symbian.cpp | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/network/kernel/qhostinfo_symbian.cpp b/src/network/kernel/qhostinfo_symbian.cpp index 5998a72..02bef40 100644 --- a/src/network/kernel/qhostinfo_symbian.cpp +++ b/src/network/kernel/qhostinfo_symbian.cpp @@ -160,13 +160,7 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName, QSharedPointer 0)) { - if (nameResult().iAddr.Family() == KAfInet) { - // IPv4 - prepend - hostAddresses.prepend(QHostAddress(qt_TDesC2QString(ipAddr))); - } else { - // IPv6 - append - hostAddresses.append(QHostAddress(qt_TDesC2QString(ipAddr))); - } + hostAddresses.append(QHostAddress(qt_TDesC2QString(ipAddr))); } } @@ -389,13 +383,7 @@ void QSymbianHostResolver::processNameResults() // Ensure that record is valid (not an alias and with length greater than 0) if (!(iNameResult().iFlags & TNameRecord::EAlias) && (ipAddr.Length() > 0)) { - if (iNameResult().iAddr.Family() == KAfInet) { - // IPv4 - prepend - hostAddresses.prepend(QHostAddress(qt_TDesC2QString(ipAddr))); - } else { - // IPv6 - append - hostAddresses.append(QHostAddress(qt_TDesC2QString(ipAddr))); - } + hostAddresses.append(QHostAddress(qt_TDesC2QString(ipAddr))); } } -- cgit v0.12 From be5e7924ec7bd6cccd626f931f55e2687910ad13 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 25 Mar 2011 13:33:54 +0000 Subject: Fix for tst_QEventLoop::processEventsExcludeSocket Depending on the OS scheduling, the TCP data sent and flushed may not have been looped back to trigger the socket's ready to read notification before the test called processEvents. This caused a failure on CI system windows 7. Added a short delay before processEvents to allow the OS to catch up. Reviewed-By: Markus Goetz --- tests/auto/qeventloop/tst_qeventloop.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/auto/qeventloop/tst_qeventloop.cpp b/tests/auto/qeventloop/tst_qeventloop.cpp index aad8390..fa2a34e 100644 --- a/tests/auto/qeventloop/tst_qeventloop.cpp +++ b/tests/auto/qeventloop/tst_qeventloop.cpp @@ -602,6 +602,7 @@ public slots: QTcpSocket *serverSocket = server->nextPendingConnection(); serverSocket->write(data, size); serverSocket->flush(); + QTest::qSleep(200); //allow the TCP/IP stack time to loopback the data, so our socket is ready to read QCoreApplication::processEvents(QEventLoop::ExcludeSocketNotifiers); testResult = dataArrived; QCoreApplication::processEvents(); //check the deferred event is processed -- cgit v0.12 From ffab45eeec38416631a2c95148dbbedb8add2d7c Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 25 Mar 2011 17:03:59 +0000 Subject: Fix new http multipart test case on symbian The new test added three reference data files required by the test, but these were not being included in the sis file. Reviewed-by: mread --- tests/auto/qnetworkreply/test/test.pro | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/tests/auto/qnetworkreply/test/test.pro b/tests/auto/qnetworkreply/test/test.pro index 80b879a..d1f6707 100644 --- a/tests/auto/qnetworkreply/test/test.pro +++ b/tests/auto/qnetworkreply/test/test.pro @@ -16,21 +16,18 @@ win32 { QT = core network RESOURCES += ../qnetworkreply.qrc -wince*: { - addFiles.files = ../empty ../rfc3252.txt ../resource - addFiles.path = . - DEPLOYMENT += addFiles -} - -symbian:{ - addFiles.files = ../empty ../rfc3252.txt ../resource ../bigfile +symbian|wince*:{ + # For cross compiled targets, reference data files need to be deployed + addFiles.files = ../empty ../rfc3252.txt ../resource ../bigfile ../*.jpg addFiles.path = . DEPLOYMENT += addFiles certFiles.files = ../certs certFiles.path = . DEPLOYMENT += certFiles +} +symbian:{ # Symbian toolchain does not support correct include semantics INCLUDEPATH+=..\\..\\..\\..\\include\\QtNetwork\\private # bigfile test case requires more heap -- cgit v0.12 From 41ffab6b5b2d9f5a578109a4ea6ca0c5df58a3eb Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 28 Mar 2011 12:54:29 +0100 Subject: Update DEF files --- src/s60installs/bwins/QtCoreu.def | 40 +++++++++++++++++++++++++++-- src/s60installs/bwins/QtGuiu.def | 6 +++++ src/s60installs/bwins/QtNetworku.def | 31 ++++++++++++++++++++++ src/s60installs/eabi/QtCoreu.def | 30 ++++++++++++++++++++++ src/s60installs/eabi/QtGuiu.def | 50 ++++++++++++++++++++++++++---------- src/s60installs/eabi/QtNetworku.def | 32 +++++++++++++++++++++++ src/s60installs/eabi/QtOpenVGu.def | 4 +++ 7 files changed, 178 insertions(+), 15 deletions(-) diff --git a/src/s60installs/bwins/QtCoreu.def b/src/s60installs/bwins/QtCoreu.def index 8265f98..f6d4271 100644 --- a/src/s60installs/bwins/QtCoreu.def +++ b/src/s60installs/bwins/QtCoreu.def @@ -1375,7 +1375,7 @@ EXPORTS ?count@QStringRef@@QBEHXZ @ 1374 NONAME ; int QStringRef::count(void) const ?countriesForLanguage@QLocale@@SA?AV?$QList@W4Country@QLocale@@@@W4Language@1@@Z @ 1375 NONAME ; class QList QLocale::countriesForLanguage(enum QLocale::Language) ?country@QLocale@@QBE?AW4Country@1@XZ @ 1376 NONAME ; enum QLocale::Country QLocale::country(void) const - ?countryId@QLocalePrivate@@QBEIXZ @ 1377 NONAME ; unsigned int QLocalePrivate::countryId(void) const + ?countryId@QLocalePrivate@@QBEIXZ @ 1377 NONAME ABSENT ; unsigned int QLocalePrivate::countryId(void) const ?countryToString@QLocale@@SA?AVQString@@W4Country@1@@Z @ 1378 NONAME ; class QString QLocale::countryToString(enum QLocale::Country) ?create@QAbstractFileEngine@@SAPAV1@ABVQString@@@Z @ 1379 NONAME ; class QAbstractFileEngine * QAbstractFileEngine::create(class QString const &) ?create@QNonContiguousByteDeviceFactory@@SAPAVQNonContiguousByteDevice@@PAVQByteArray@@@Z @ 1380 NONAME ; class QNonContiguousByteDevice * QNonContiguousByteDeviceFactory::create(class QByteArray *) @@ -2331,7 +2331,7 @@ EXPORTS ?killTimer@QObject@@QAEXH@Z @ 2330 NONAME ; void QObject::killTimer(int) ?killTimer@QTimer@@AAEXH@Z @ 2331 NONAME ; void QTimer::killTimer(int) ?language@QLocale@@QBE?AW4Language@1@XZ @ 2332 NONAME ; enum QLocale::Language QLocale::language(void) const - ?languageId@QLocalePrivate@@QBEIXZ @ 2333 NONAME ; unsigned int QLocalePrivate::languageId(void) const + ?languageId@QLocalePrivate@@QBEIXZ @ 2333 NONAME ABSENT ; unsigned int QLocalePrivate::languageId(void) const ?languageToString@QLocale@@SA?AVQString@@W4Language@1@@Z @ 2334 NONAME ; class QString QLocale::languageToString(enum QLocale::Language) ?lastIndexIn@QRegExp@@QBEHABVQString@@HW4CaretMode@1@@Z @ 2335 NONAME ; int QRegExp::lastIndexIn(class QString const &, int, enum QRegExp::CaretMode) const ?lastIndexOf@QByteArray@@QBEHABV1@H@Z @ 2336 NONAME ; int QByteArray::lastIndexOf(class QByteArray const &, int) const @@ -4631,3 +4631,39 @@ EXPORTS ?removeSocket@QSymbianSocketManager@@QAE_NABVRSocket@@@Z @ 4630 NONAME ; bool QSymbianSocketManager::removeSocket(class RSocket const &) ?started@QAnimationDriver@@MAEXXZ @ 4631 NONAME ; void QAnimationDriver::started(void) ?stopped@QAnimationDriver@@MAEXXZ @ 4632 NONAME ; void QAnimationDriver::stopped(void) + ?toCurrencyString@QLocale@@QBE?AVQString@@NABV2@@Z @ 4633 NONAME ; class QString QLocale::toCurrencyString(double, class QString const &) const + ?quoteString@QLocale@@QBE?AVQString@@ABVQStringRef@@W4QuotationStyle@1@@Z @ 4634 NONAME ; class QString QLocale::quoteString(class QStringRef const &, enum QLocale::QuotationStyle) const + ?toCurrencyString@QLocale@@QBE?AVQString@@FABV2@@Z @ 4635 NONAME ; class QString QLocale::toCurrencyString(short, class QString const &) const + ?countryCode@QLocalePrivate@@QBE?AVQString@@XZ @ 4636 NONAME ; class QString QLocalePrivate::countryCode(void) const + ?toCurrencyString@QLocale@@QBE?AVQString@@IABV2@@Z @ 4637 NONAME ; class QString QLocale::toCurrencyString(unsigned int, class QString const &) const + ?longLongToString@QLocalePrivate@@SA?AVQString@@VQChar@@000_JHHHI@Z @ 4638 NONAME ; class QString QLocalePrivate::longLongToString(class QChar, class QChar, class QChar, class QChar, long long, int, int, int, unsigned int) + ?codeToScript@QLocalePrivate@@SA?AW4Script@QLocale@@ABVQString@@@Z @ 4639 NONAME ; enum QLocale::Script QLocalePrivate::codeToScript(class QString const &) + ?bcp47Name@QLocale@@QBE?AVQString@@XZ @ 4640 NONAME ; class QString QLocale::bcp47Name(void) const + ?quoteString@QLocale@@QBE?AVQString@@ABV2@W4QuotationStyle@1@@Z @ 4641 NONAME ; class QString QLocale::quoteString(class QString const &, enum QLocale::QuotationStyle) const + ?unsLongLongToString@QLocalePrivate@@SA?AVQString@@VQChar@@00_KHHHI@Z @ 4642 NONAME ; class QString QLocalePrivate::unsLongLongToString(class QChar, class QChar, class QChar, unsigned long long, int, int, int, unsigned int) + ?toCurrencyString@QLocale@@QBE?AVQString@@_KABV2@@Z @ 4643 NONAME ; class QString QLocale::toCurrencyString(unsigned long long, class QString const &) const + ?firstDayOfWeek@QLocale@@QBE?AW4DayOfWeek@Qt@@XZ @ 4644 NONAME ; enum Qt::DayOfWeek QLocale::firstDayOfWeek(void) const + ?createSeparatedList@QLocale@@QBE?AVQString@@ABVQStringList@@@Z @ 4645 NONAME ; class QString QLocale::createSeparatedList(class QStringList const &) const + ?codeToCountry@QLocalePrivate@@SA?AW4Country@QLocale@@ABVQString@@@Z @ 4646 NONAME ; enum QLocale::Country QLocalePrivate::codeToCountry(class QString const &) + ?scriptCode@QLocalePrivate@@QBE?AVQString@@XZ @ 4647 NONAME ; class QString QLocalePrivate::scriptCode(void) const + ?scriptToString@QLocale@@SA?AVQString@@W4Script@1@@Z @ 4648 NONAME ; class QString QLocale::scriptToString(enum QLocale::Script) + ?script@QLocale@@QBE?AW4Script@1@XZ @ 4649 NONAME ; enum QLocale::Script QLocale::script(void) const + ?codeToLanguage@QLocalePrivate@@SA?AW4Language@QLocale@@ABVQString@@@Z @ 4650 NONAME ; enum QLocale::Language QLocalePrivate::codeToLanguage(class QString const &) + ?weekdays@QLocale@@QBE?AV?$QList@W4DayOfWeek@Qt@@@@XZ @ 4651 NONAME ; class QList QLocale::weekdays(void) const + ?getLangAndCountry@QLocalePrivate@@SAXABVQString@@AAW4Language@QLocale@@AAW4Script@4@AAW4Country@4@@Z @ 4652 NONAME ; void QLocalePrivate::getLangAndCountry(class QString const &, enum QLocale::Language &, enum QLocale::Script &, enum QLocale::Country &) + ?bcp47Name@QLocalePrivate@@QBE?AVQString@@XZ @ 4653 NONAME ; class QString QLocalePrivate::bcp47Name(void) const + ?toCurrencyString@QLocale@@QBE?AVQString@@HABV2@@Z @ 4654 NONAME ; class QString QLocale::toCurrencyString(int, class QString const &) const + ?matchingLocales@QLocale@@SA?AVQStringList@@W4Language@1@W4Script@1@W4Country@1@@Z @ 4655 NONAME ; class QStringList QLocale::matchingLocales(enum QLocale::Language, enum QLocale::Script, enum QLocale::Country) + ?languageCode@QLocalePrivate@@QBE?AVQString@@XZ @ 4656 NONAME ; class QString QLocalePrivate::languageCode(void) const + ?toCurrencyString@QLocale@@QBE?AVQString@@GABV2@@Z @ 4657 NONAME ; class QString QLocale::toCurrencyString(unsigned short, class QString const &) const + ?doubleToString@QLocalePrivate@@SA?AVQString@@VQChar@@00000NHW4DoubleForm@1@HI@Z @ 4658 NONAME ; class QString QLocalePrivate::doubleToString(class QChar, class QChar, class QChar, class QChar, class QChar, class QChar, double, int, enum QLocalePrivate::DoubleForm, int, unsigned int) + ?currencySymbol@QLocale@@QBE?AVQString@@W4CurrencySymbolFormat@1@@Z @ 4659 NONAME ; class QString QLocale::currencySymbol(enum QLocale::CurrencySymbolFormat) const + ?uiLanguages@QLocale@@QBE?AVQStringList@@XZ @ 4660 NONAME ; class QStringList QLocale::uiLanguages(void) const + ?findLocale@QLocalePrivate@@SAPBU1@W4Language@QLocale@@W4Script@3@W4Country@3@@Z @ 4661 NONAME ; struct QLocalePrivate const * QLocalePrivate::findLocale(enum QLocale::Language, enum QLocale::Script, enum QLocale::Country) + ?load@QTranslator@@QAE_NABVQLocale@@ABVQString@@111@Z @ 4662 NONAME ; bool QTranslator::load(class QLocale const &, class QString const &, class QString const &, class QString const &, class QString const &) + ??0QLocale@@QAE@W4Language@0@W4Script@0@W4Country@0@@Z @ 4663 NONAME ; QLocale::QLocale(enum QLocale::Language, enum QLocale::Script, enum QLocale::Country) + ?languageId@QLocalePrivate@@QBEGXZ @ 4664 NONAME ; unsigned short QLocalePrivate::languageId(void) const + ?countryId@QLocalePrivate@@QBEGXZ @ 4665 NONAME ; unsigned short QLocalePrivate::countryId(void) const + ?toCurrencyString@QLocale@@QBE?AVQString@@_JABV2@@Z @ 4666 NONAME ; class QString QLocale::toCurrencyString(long long, class QString const &) const + ?toCurrencyString@QLocale@@QBE?AVQString@@MABV2@@Z @ 4667 NONAME ; class QString QLocale::toCurrencyString(float, class QString const &) const + diff --git a/src/s60installs/bwins/QtGuiu.def b/src/s60installs/bwins/QtGuiu.def index 0c3d1a2..0be8a53 100644 --- a/src/s60installs/bwins/QtGuiu.def +++ b/src/s60installs/bwins/QtGuiu.def @@ -13203,3 +13203,9 @@ EXPORTS ?byteCount@QVolatileImage@@QBEHXZ @ 13202 NONAME ; int QVolatileImage::byteCount(void) const ??0QVolatileImage@@QAE@ABV0@@Z @ 13203 NONAME ; QVolatileImage::QVolatileImage(class QVolatileImage const &) ?depth@QVolatileImage@@QBEHXZ @ 13204 NONAME ; int QVolatileImage::depth(void) const + ?setTabsClosable@QMdiArea@@QAEX_N@Z @ 13205 NONAME ; void QMdiArea::setTabsClosable(bool) + ?qt_s60_setPartialScreenInputMode@@YAX_N@Z @ 13206 NONAME ; void qt_s60_setPartialScreenInputMode(bool) + ?setTabsMovable@QMdiArea@@QAEX_N@Z @ 13207 NONAME ; void QMdiArea::setTabsMovable(bool) + ?tabsMovable@QMdiArea@@QBE_NXZ @ 13208 NONAME ; bool QMdiArea::tabsMovable(void) const + ?tabsClosable@QMdiArea@@QBE_NXZ @ 13209 NONAME ; bool QMdiArea::tabsClosable(void) const + diff --git a/src/s60installs/bwins/QtNetworku.def b/src/s60installs/bwins/QtNetworku.def index 3f8f6d2..dbe43d7 100644 --- a/src/s60installs/bwins/QtNetworku.def +++ b/src/s60installs/bwins/QtNetworku.def @@ -1164,4 +1164,35 @@ EXPORTS ?nativeSession@QNetworkSessionPrivate@@SAPAVRConnection@@AAVQNetworkSession@@@Z @ 1163 NONAME ; class RConnection * QNetworkSessionPrivate::nativeSession(class QNetworkSession &) ?nativeOpenSocket@QNetworkSessionPrivate@@SAHAAVQNetworkSession@@AAVRSocket@@III@Z @ 1164 NONAME ; int QNetworkSessionPrivate::nativeOpenSocket(class QNetworkSession &, class RSocket &, unsigned int, unsigned int, unsigned int) ?nativeOpenHostResolver@QNetworkSessionPrivate@@SAHAAVQNetworkSession@@AAVRHostResolver@@II@Z @ 1165 NONAME ; int QNetworkSessionPrivate::nativeOpenHostResolver(class QNetworkSession &, class RHostResolver &, unsigned int, unsigned int) + ??_EQHttpMultiPart@@UAE@I@Z @ 1166 NONAME ; QHttpMultiPart::~QHttpMultiPart(unsigned int) + ??1QHttpPart@@QAE@XZ @ 1167 NONAME ; QHttpPart::~QHttpPart(void) + ?trUtf8@QHttpMultiPart@@SA?AVQString@@PBD0@Z @ 1168 NONAME ; class QString QHttpMultiPart::trUtf8(char const *, char const *) + ??0QHttpPart@@QAE@ABV0@@Z @ 1169 NONAME ; QHttpPart::QHttpPart(class QHttpPart const &) + ?setBody@QHttpPart@@QAEXABVQByteArray@@@Z @ 1170 NONAME ; void QHttpPart::setBody(class QByteArray const &) + ?trUtf8@QHttpMultiPart@@SA?AVQString@@PBD0H@Z @ 1171 NONAME ; class QString QHttpMultiPart::trUtf8(char const *, char const *, int) + ?staticMetaObject@QHttpMultiPart@@2UQMetaObject@@B @ 1172 NONAME ; struct QMetaObject const QHttpMultiPart::staticMetaObject + ??4QHttpPart@@QAEAAV0@ABV0@@Z @ 1173 NONAME ; class QHttpPart & QHttpPart::operator=(class QHttpPart const &) + ?append@QHttpMultiPart@@QAEXABVQHttpPart@@@Z @ 1174 NONAME ; void QHttpMultiPart::append(class QHttpPart const &) + ?setContentType@QHttpMultiPart@@QAEXW4ContentType@1@@Z @ 1175 NONAME ; void QHttpMultiPart::setContentType(enum QHttpMultiPart::ContentType) + ?d_func@QHttpMultiPart@@AAEPAVQHttpMultiPartPrivate@@XZ @ 1176 NONAME ; class QHttpMultiPartPrivate * QHttpMultiPart::d_func(void) + ??9QHttpPart@@QBE_NABV0@@Z @ 1177 NONAME ; bool QHttpPart::operator!=(class QHttpPart const &) const + ??0QHttpMultiPart@@QAE@W4ContentType@0@PAVQObject@@@Z @ 1178 NONAME ; QHttpMultiPart::QHttpMultiPart(enum QHttpMultiPart::ContentType, class QObject *) + ??0QHttpPart@@QAE@XZ @ 1179 NONAME ; QHttpPart::QHttpPart(void) + ?post@QNetworkAccessManager@@QAEPAVQNetworkReply@@ABVQNetworkRequest@@PAVQHttpMultiPart@@@Z @ 1180 NONAME ; class QNetworkReply * QNetworkAccessManager::post(class QNetworkRequest const &, class QHttpMultiPart *) + ??0QHttpMultiPart@@QAE@PAVQObject@@@Z @ 1181 NONAME ; QHttpMultiPart::QHttpMultiPart(class QObject *) + ??8QHttpPart@@QBE_NABV0@@Z @ 1182 NONAME ; bool QHttpPart::operator==(class QHttpPart const &) const + ?setBodyDevice@QHttpPart@@QAEXPAVQIODevice@@@Z @ 1183 NONAME ; void QHttpPart::setBodyDevice(class QIODevice *) + ?getStaticMetaObject@QHttpMultiPart@@SAABUQMetaObject@@XZ @ 1184 NONAME ; struct QMetaObject const & QHttpMultiPart::getStaticMetaObject(void) + ?qt_metacast@QHttpMultiPart@@UAEPAXPBD@Z @ 1185 NONAME ; void * QHttpMultiPart::qt_metacast(char const *) + ?put@QNetworkAccessManager@@QAEPAVQNetworkReply@@ABVQNetworkRequest@@PAVQHttpMultiPart@@@Z @ 1186 NONAME ; class QNetworkReply * QNetworkAccessManager::put(class QNetworkRequest const &, class QHttpMultiPart *) + ?tr@QHttpMultiPart@@SA?AVQString@@PBD0@Z @ 1187 NONAME ; class QString QHttpMultiPart::tr(char const *, char const *) + ?qt_metacall@QHttpMultiPart@@UAEHW4Call@QMetaObject@@HPAPAX@Z @ 1188 NONAME ; int QHttpMultiPart::qt_metacall(enum QMetaObject::Call, int, void * *) + ?boundary@QHttpMultiPart@@QBE?AVQByteArray@@XZ @ 1189 NONAME ; class QByteArray QHttpMultiPart::boundary(void) const + ?setRawHeader@QHttpPart@@QAEXABVQByteArray@@0@Z @ 1190 NONAME ; void QHttpPart::setRawHeader(class QByteArray const &, class QByteArray const &) + ?metaObject@QHttpMultiPart@@UBEPBUQMetaObject@@XZ @ 1191 NONAME ; struct QMetaObject const * QHttpMultiPart::metaObject(void) const + ?setHeader@QHttpPart@@QAEXW4KnownHeaders@QNetworkRequest@@ABVQVariant@@@Z @ 1192 NONAME ; void QHttpPart::setHeader(enum QNetworkRequest::KnownHeaders, class QVariant const &) + ??1QHttpMultiPart@@UAE@XZ @ 1193 NONAME ; QHttpMultiPart::~QHttpMultiPart(void) + ?d_func@QHttpMultiPart@@ABEPBVQHttpMultiPartPrivate@@XZ @ 1194 NONAME ; class QHttpMultiPartPrivate const * QHttpMultiPart::d_func(void) const + ?tr@QHttpMultiPart@@SA?AVQString@@PBD0H@Z @ 1195 NONAME ; class QString QHttpMultiPart::tr(char const *, char const *, int) + ?setBoundary@QHttpMultiPart@@QAEXABVQByteArray@@@Z @ 1196 NONAME ; void QHttpMultiPart::setBoundary(class QByteArray const &) diff --git a/src/s60installs/eabi/QtCoreu.def b/src/s60installs/eabi/QtCoreu.def index c5dd0ac..1bf52b1 100644 --- a/src/s60installs/eabi/QtCoreu.def +++ b/src/s60installs/eabi/QtCoreu.def @@ -3834,3 +3834,33 @@ EXPORTS gzungetc @ 3833 NONAME _ZN16QAnimationDriverC1EP7QObject @ 3834 NONAME _ZN16QAnimationDriverC1ER23QAnimationDriverPrivateP7QObject @ 3835 NONAME + _ZN11QTranslator4loadERK7QLocaleRK7QStringS5_S5_S5_ @ 3836 NONAME + _ZN14QLocalePrivate10findLocaleEN7QLocale8LanguageENS0_6ScriptENS0_7CountryE @ 3837 NONAME + _ZN14QLocalePrivate12codeToScriptERK7QString @ 3838 NONAME + _ZN14QLocalePrivate13codeToCountryERK7QString @ 3839 NONAME + _ZN14QLocalePrivate14codeToLanguageERK7QString @ 3840 NONAME + _ZN14QLocalePrivate14doubleToStringE5QCharS0_S0_S0_S0_S0_diNS_10DoubleFormEij @ 3841 NONAME + _ZN14QLocalePrivate16longLongToStringE5QCharS0_S0_S0_xiiij @ 3842 NONAME + _ZN14QLocalePrivate17getLangAndCountryERK7QStringRN7QLocale8LanguageERNS3_6ScriptERNS3_7CountryE @ 3843 NONAME + _ZN14QLocalePrivate19unsLongLongToStringE5QCharS0_S0_yiiij @ 3844 NONAME + _ZN7QLocale14scriptToStringENS_6ScriptE @ 3845 NONAME + _ZN7QLocale15matchingLocalesENS_8LanguageENS_6ScriptENS_7CountryE @ 3846 NONAME + _ZN7QLocaleC1ENS_8LanguageENS_6ScriptENS_7CountryE @ 3847 NONAME + _ZN7QLocaleC2ENS_8LanguageENS_6ScriptENS_7CountryE @ 3848 NONAME + _ZNK14QLocalePrivate10scriptCodeEv @ 3849 NONAME + _ZNK14QLocalePrivate11countryCodeEv @ 3850 NONAME + _ZNK14QLocalePrivate12languageCodeEv @ 3851 NONAME + _ZNK14QLocalePrivate9bcp47NameEv @ 3852 NONAME + _ZNK7QLocale11quoteStringERK10QStringRefNS_14QuotationStyleE @ 3853 NONAME + _ZNK7QLocale11quoteStringERK7QStringNS_14QuotationStyleE @ 3854 NONAME + _ZNK7QLocale11uiLanguagesEv @ 3855 NONAME + _ZNK7QLocale14currencySymbolENS_20CurrencySymbolFormatE @ 3856 NONAME + _ZNK7QLocale14firstDayOfWeekEv @ 3857 NONAME + _ZNK7QLocale16toCurrencyStringEdRK7QString @ 3858 NONAME + _ZNK7QLocale16toCurrencyStringExRK7QString @ 3859 NONAME + _ZNK7QLocale16toCurrencyStringEyRK7QString @ 3860 NONAME + _ZNK7QLocale19createSeparatedListERK11QStringList @ 3861 NONAME + _ZNK7QLocale6scriptEv @ 3862 NONAME + _ZNK7QLocale8weekdaysEv @ 3863 NONAME + _ZNK7QLocale9bcp47NameEv @ 3864 NONAME + diff --git a/src/s60installs/eabi/QtGuiu.def b/src/s60installs/eabi/QtGuiu.def index 561e332..2ffb98e 100644 --- a/src/s60installs/eabi/QtGuiu.def +++ b/src/s60installs/eabi/QtGuiu.def @@ -12360,17 +12360,41 @@ EXPORTS _ZN14QVolatileImageD2Ev @ 12359 NONAME _ZN14QVolatileImageaSERKS_ @ 12360 NONAME _ZN15QGraphicsSystem22releaseCachedResourcesEv @ 12361 NONAME - _ZNK14QVolatileImage12bytesPerLineEv @ 12374 NONAME - _ZNK14QVolatileImage13endDataAccessEb @ 12375 NONAME - _ZNK14QVolatileImage15beginDataAccessEv @ 12376 NONAME - _ZNK14QVolatileImage15hasAlphaChannelEv @ 12377 NONAME - _ZNK14QVolatileImage20duplicateNativeImageEv @ 12378 NONAME - _ZNK14QVolatileImage5depthEv @ 12379 NONAME - _ZNK14QVolatileImage5widthEv @ 12380 NONAME - _ZNK14QVolatileImage6formatEv @ 12381 NONAME - _ZNK14QVolatileImage6heightEv @ 12382 NONAME - _ZNK14QVolatileImage6isNullEv @ 12383 NONAME - _ZNK14QVolatileImage7toImageEv @ 12384 NONAME - _ZNK14QVolatileImage9byteCountEv @ 12385 NONAME - _ZNK14QVolatileImage9constBitsEv @ 12386 NONAME + _Z32qt_s60_setPartialScreenInputModeb @ 12362 NONAME + _ZN17QInternalMimeData11canReadDataERK7QString @ 12363 NONAME + _ZN17QInternalMimeData11qt_metacallEN11QMetaObject4CallEiPPv @ 12364 NONAME + _ZN17QInternalMimeData11qt_metacastEPKc @ 12365 NONAME + _ZN17QInternalMimeData13formatsHelperEPK9QMimeData @ 12366 NONAME + _ZN17QInternalMimeData15hasFormatHelperERK7QStringPK9QMimeData @ 12367 NONAME + _ZN17QInternalMimeData16renderDataHelperERK7QStringPK9QMimeData @ 12368 NONAME + _ZN17QInternalMimeData16staticMetaObjectE @ 12369 NONAME DATA 16 + _ZN17QInternalMimeData19getStaticMetaObjectEv @ 12370 NONAME + _ZN17QInternalMimeDataC2Ev @ 12371 NONAME + _ZN17QInternalMimeDataD0Ev @ 12372 NONAME + _ZN17QInternalMimeDataD1Ev @ 12373 NONAME + _ZN17QInternalMimeDataD2Ev @ 12374 NONAME + _ZN8QMdiArea14setTabsMovableEb @ 12375 NONAME + _ZN8QMdiArea15setTabsClosableEb @ 12376 NONAME + _ZNK14QVolatileImage12bytesPerLineEv @ 12377 NONAME + _ZNK14QVolatileImage13endDataAccessEb @ 12378 NONAME + _ZNK14QVolatileImage15beginDataAccessEv @ 12379 NONAME + _ZNK14QVolatileImage15hasAlphaChannelEv @ 12380 NONAME + _ZNK14QVolatileImage20duplicateNativeImageEv @ 12381 NONAME + _ZNK14QVolatileImage5depthEv @ 12382 NONAME + _ZNK14QVolatileImage5widthEv @ 12383 NONAME + _ZNK14QVolatileImage6formatEv @ 12384 NONAME + _ZNK14QVolatileImage6heightEv @ 12385 NONAME + _ZNK14QVolatileImage6isNullEv @ 12386 NONAME + _ZNK14QVolatileImage7toImageEv @ 12387 NONAME + _ZNK14QVolatileImage9byteCountEv @ 12388 NONAME + _ZNK14QVolatileImage9constBitsEv @ 12389 NONAME + _ZNK14QWidgetPrivate20assignedInputContextEv @ 12390 NONAME + _ZNK17QInternalMimeData10metaObjectEv @ 12391 NONAME + _ZNK17QInternalMimeData12retrieveDataERK7QStringN8QVariant4TypeE @ 12392 NONAME + _ZNK17QInternalMimeData7formatsEv @ 12393 NONAME + _ZNK17QInternalMimeData9hasFormatERK7QString @ 12394 NONAME + _ZNK8QMdiArea11tabsMovableEv @ 12395 NONAME + _ZNK8QMdiArea12tabsClosableEv @ 12396 NONAME + _ZTI17QInternalMimeData @ 12397 NONAME + _ZTV17QInternalMimeData @ 12398 NONAME diff --git a/src/s60installs/eabi/QtNetworku.def b/src/s60installs/eabi/QtNetworku.def index 672ae84..47d251d 100644 --- a/src/s60installs/eabi/QtNetworku.def +++ b/src/s60installs/eabi/QtNetworku.def @@ -1186,4 +1186,36 @@ EXPORTS _ZN22QNetworkSessionPrivate16nativeOpenSocketER15QNetworkSessionR7RSocketjjj @ 1185 NONAME _ZN22QNetworkSessionPrivate22nativeOpenHostResolverER15QNetworkSessionR13RHostResolverjj @ 1186 NONAME _ZNK10QSslSocket14peerVerifyNameEv @ 1187 NONAME + _ZN14QHttpMultiPart11qt_metacallEN11QMetaObject4CallEiPPv @ 1188 NONAME + _ZN14QHttpMultiPart11qt_metacastEPKc @ 1189 NONAME + _ZN14QHttpMultiPart11setBoundaryERK10QByteArray @ 1190 NONAME + _ZN14QHttpMultiPart14setContentTypeENS_11ContentTypeE @ 1191 NONAME + _ZN14QHttpMultiPart16staticMetaObjectE @ 1192 NONAME DATA 16 + _ZN14QHttpMultiPart19getStaticMetaObjectEv @ 1193 NONAME + _ZN14QHttpMultiPart6appendERK9QHttpPart @ 1194 NONAME + _ZN14QHttpMultiPartC1ENS_11ContentTypeEP7QObject @ 1195 NONAME + _ZN14QHttpMultiPartC1EP7QObject @ 1196 NONAME + _ZN14QHttpMultiPartC2ENS_11ContentTypeEP7QObject @ 1197 NONAME + _ZN14QHttpMultiPartC2EP7QObject @ 1198 NONAME + _ZN14QHttpMultiPartD0Ev @ 1199 NONAME + _ZN14QHttpMultiPartD1Ev @ 1200 NONAME + _ZN14QHttpMultiPartD2Ev @ 1201 NONAME + _ZN21QNetworkAccessManager3putERK15QNetworkRequestP14QHttpMultiPart @ 1202 NONAME + _ZN21QNetworkAccessManager4postERK15QNetworkRequestP14QHttpMultiPart @ 1203 NONAME + _ZN9QHttpPart12setRawHeaderERK10QByteArrayS2_ @ 1204 NONAME + _ZN9QHttpPart13setBodyDeviceEP9QIODevice @ 1205 NONAME + _ZN9QHttpPart7setBodyERK10QByteArray @ 1206 NONAME + _ZN9QHttpPart9setHeaderEN15QNetworkRequest12KnownHeadersERK8QVariant @ 1207 NONAME + _ZN9QHttpPartC1ERKS_ @ 1208 NONAME + _ZN9QHttpPartC1Ev @ 1209 NONAME + _ZN9QHttpPartC2ERKS_ @ 1210 NONAME + _ZN9QHttpPartC2Ev @ 1211 NONAME + _ZN9QHttpPartD1Ev @ 1212 NONAME + _ZN9QHttpPartD2Ev @ 1213 NONAME + _ZN9QHttpPartaSERKS_ @ 1214 NONAME + _ZNK14QHttpMultiPart10metaObjectEv @ 1215 NONAME + _ZNK14QHttpMultiPart8boundaryEv @ 1216 NONAME + _ZNK9QHttpParteqERKS_ @ 1217 NONAME + _ZTI14QHttpMultiPart @ 1218 NONAME + _ZTV14QHttpMultiPart @ 1219 NONAME diff --git a/src/s60installs/eabi/QtOpenVGu.def b/src/s60installs/eabi/QtOpenVGu.def index e05cc79..72f11fc 100644 --- a/src/s60installs/eabi/QtOpenVGu.def +++ b/src/s60installs/eabi/QtOpenVGu.def @@ -209,4 +209,8 @@ EXPORTS _ZN13QVGPixmapData12updateSerialEv @ 208 NONAME ABSENT _ZN13QVGPixmapData4copyEPK11QPixmapDataRK5QRect @ 209 NONAME ABSENT _ZNK13QVGPixmapData11idealFormatEP6QImage6QFlagsIN2Qt19ImageConversionFlagEE @ 210 NONAME ABSENT + _ZN13QVGPixmapData24releaseNativeImageHandleEv @ 211 NONAME + _ZN13QVGPixmapData25initFromNativeImageHandleEPvRK7QString @ 212 NONAME + _ZN13QVGPixmapData35createFromNativeImageHandleProviderEv @ 213 NONAME + _ZNK13QVGPixmapData14ensureReadbackEb @ 214 NONAME -- cgit v0.12 From bcbce977fa7a0d61de5f17e6727eba5a823bc3bb Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 25 Mar 2011 18:07:15 +0000 Subject: Performance: use select poll for timeout of 0ms A timer of 0ms completes on the next kernel tick (up to 0.999ms) There is a poll GetOpt we can use instead that doesn't require using a timer to cancel the select ioctl. Reviewed-by: Markus Goetz --- src/network/socket/qsymbiansocketengine.cpp | 67 ++++++++++++++++------------- 1 file changed, 37 insertions(+), 30 deletions(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index 58e8d9f..af755a9 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -1105,39 +1105,46 @@ int QSymbianSocketEnginePrivate::nativeSelect(int timeout, bool checkRead, bool selectFlags() |= KSockSelectRead; if (checkWrite) selectFlags() |= KSockSelectWrite; - TRequestStatus selectStat; - nativeSocket.Ioctl(KIOctlSelect, selectStat, &selectFlags, KSOLSocket); - - if (timeout < 0) - User::WaitForRequest(selectStat); //negative means no timeout - else { - if (!selectTimer.Handle()) - qt_symbian_throwIfError(selectTimer.CreateLocal()); - TRequestStatus timerStat; - selectTimer.HighRes(timerStat, timeout * 1000); - User::WaitForRequest(timerStat, selectStat); - if (selectStat == KRequestPending) { - nativeSocket.CancelIoctl(); - //CancelIoctl completes the request (most likely with KErrCancel) - //We need to wait for this to keep the thread semaphore balanced (or active scheduler will panic) - User::WaitForRequest(selectStat); - //restart asynchronous notifier (only one IOCTL allowed at a time) - if (asyncSelect) - asyncSelect->IssueRequest(); -#ifdef QNATIVESOCKETENGINE_DEBUG - qDebug() << "QSymbianSocketEnginePrivate::nativeSelect: select timeout"; -#endif - return 0; //timeout - } else { - selectTimer.Cancel(); - User::WaitForRequest(timerStat); + TInt err; + if (timeout == 0) { + //if timeout is zero, poll + err = nativeSocket.GetOpt(KSOSelectPoll, KSOLSocket, selectFlags); + } else { + TRequestStatus selectStat; + nativeSocket.Ioctl(KIOctlSelect, selectStat, &selectFlags, KSOLSocket); + + if (timeout < 0) + User::WaitForRequest(selectStat); //negative means no timeout + else { + if (!selectTimer.Handle()) + qt_symbian_throwIfError(selectTimer.CreateLocal()); + TRequestStatus timerStat; + selectTimer.HighRes(timerStat, timeout * 1000); + User::WaitForRequest(timerStat, selectStat); + if (selectStat == KRequestPending) { + nativeSocket.CancelIoctl(); + //CancelIoctl completes the request (most likely with KErrCancel) + //We need to wait for this to keep the thread semaphore balanced (or active scheduler will panic) + User::WaitForRequest(selectStat); + //restart asynchronous notifier (only one IOCTL allowed at a time) + if (asyncSelect) + asyncSelect->IssueRequest(); + #ifdef QNATIVESOCKETENGINE_DEBUG + qDebug() << "QSymbianSocketEnginePrivate::nativeSelect: select timeout"; + #endif + return 0; //timeout + } else { + selectTimer.Cancel(); + User::WaitForRequest(timerStat); + } } + + #ifdef QNATIVESOCKETENGINE_DEBUG + qDebug() << "QSymbianSocketEnginePrivate::nativeSelect: select status" << selectStat.Int() << (int)selectFlags(); + #endif + err = selectStat.Int(); } -#ifdef QNATIVESOCKETENGINE_DEBUG - qDebug() << "QSymbianSocketEnginePrivate::nativeSelect: select status" << selectStat.Int() << (int)selectFlags(); -#endif - TInt err = selectStat.Int(); if (!err && (selectFlags() & KSockSelectExcept)) { nativeSocket.GetOpt(KSOSelectLastError, KSOLSocket, err); #ifdef QNATIVESOCKETENGINE_DEBUG -- cgit v0.12 From a970c3334bba3b7e1e27fa8b1b4ad4e4724ce015 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 28 Mar 2011 15:58:34 +0100 Subject: Bearer support for autotests Start default bearer when running network self test Fix typo in qnetworkreply test Reviewed-by: Markus Goetz --- tests/auto/networkselftest/tst_networkselftest.cpp | 26 ++++++++++++++++++++++ tests/auto/qnetworkreply/tst_qnetworkreply.cpp | 2 +- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/tests/auto/networkselftest/tst_networkselftest.cpp b/tests/auto/networkselftest/tst_networkselftest.cpp index 64de64a..ed070d7 100644 --- a/tests/auto/networkselftest/tst_networkselftest.cpp +++ b/tests/auto/networkselftest/tst_networkselftest.cpp @@ -44,6 +44,12 @@ #include +#ifndef QT_NO_BEARERMANAGEMENT +#include +#include +#include +#endif + #ifdef Q_OS_SYMBIAN // In Symbian OS test data is located in applications private dir // Current path (C:\private\) contains only ascii chars @@ -64,6 +70,7 @@ public: QHostAddress serverIpAddress(); private slots: + void initTestCase(); void hostTest(); void dnsResolution_data(); void dnsResolution(); @@ -91,6 +98,12 @@ private slots: // ssl supported test void supportsSsl(); +private: +#ifndef QT_NO_BEARERMANAGEMENT + QNetworkConfigurationManager *netConfMan; + QNetworkConfiguration networkConfiguration; + QScopedPointer networkSession; +#endif }; class Chat @@ -354,6 +367,19 @@ QHostAddress tst_NetworkSelfTest::serverIpAddress() return cachedIpAddress; } +void tst_NetworkSelfTest::initTestCase() +{ +#ifndef QT_NO_BEARERMANAGEMENT + netConfMan = new QNetworkConfigurationManager(this); + networkConfiguration = netConfMan->defaultConfiguration(); + networkSession.reset(new QNetworkSession(networkConfiguration)); + if (!networkSession->isOpen()) { + networkSession->open(); + QVERIFY(networkSession->waitForOpened(30000)); + } +#endif +} + void tst_NetworkSelfTest::hostTest() { // this is a localhost self-test diff --git a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp index 4b8dc3b..11f4fc3 100644 --- a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp @@ -143,7 +143,7 @@ class tst_QNetworkReply: public QObject QSslConfiguration storedSslConfiguration; QList storedExpectedSslErrors; #endif -#ifndef QT_NO_BEARER_MANAGEMENT +#ifndef QT_NO_BEARERMANAGEMENT QNetworkConfigurationManager *netConfMan; QNetworkConfiguration networkConfiguration; QScopedPointer networkSession; -- cgit v0.12 From aa67255608d7b752fcdd6fcbabf518dbdbf4f98e Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 28 Mar 2011 16:02:10 +0100 Subject: Symbian workaround for networkselftest The frox ftp proxy closes connections using TCP RST instead of a normal TCP FIN. On symbian, this causes the received but unacknowledged preceding packet to be discarded (the "221 Goodbye" ftp response). As QNAM and QFTP don't care about this, the network self test won't either. (only for symbian, as windows and unix TCP/IP stacks retain the unacknowledged packet in the receive queue) Reviewed-by: Markus Goetz --- tests/auto/networkselftest/tst_networkselftest.cpp | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/tests/auto/networkselftest/tst_networkselftest.cpp b/tests/auto/networkselftest/tst_networkselftest.cpp index ed070d7..f40ea3e 100644 --- a/tests/auto/networkselftest/tst_networkselftest.cpp +++ b/tests/auto/networkselftest/tst_networkselftest.cpp @@ -495,7 +495,8 @@ void tst_NetworkSelfTest::fileLineEndingTest() static QList ftpChat(const QByteArray &userSuffix = QByteArray()) { - return QList() << Chat::expect("220") + QList rv; + rv << Chat::expect("220") << Chat::discardUntil("\r\n") << Chat::send("USER anonymous" + userSuffix + "\r\n") << Chat::expect("331") @@ -530,10 +531,15 @@ static QList ftpChat(const QByteArray &userSuffix = QByteArray()) // << Chat::send("SIZE nonASCII/german_\344\366\374\304\326\334\337\r\n") // << Chat::expect("213 40\r\n") - << Chat::send("QUIT\r\n") - << Chat::expect("221") - << Chat::discardUntil("\r\n") - << Chat::RemoteDisconnect; + << Chat::send("QUIT\r\n"); +#ifdef Q_OS_SYMBIAN + if (userSuffix.length() == 0) // received but unacknowledged packets are discarded by TCP RST, so this doesn't work with frox proxy +#endif + rv << Chat::expect("221") + << Chat::discardUntil("\r\n"); + + rv << Chat::RemoteDisconnect; + return rv; } void tst_NetworkSelfTest::ftpServer() -- cgit v0.12 From b58eb992f162efc9db6cada9f037f7a0acbe5c57 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 28 Mar 2011 17:53:45 +0100 Subject: Ensure shared network session deleted from correct thread Due to threaded http, the shared QNetworkSession can have its last reference removed from a http delegate thread. To avoid this deadlocking use a deleteLater custom deleter so that the QNS is deleted from the thread it has affinity for. Reviewed-by: Markus Goetz --- src/network/bearer/qsharednetworksession.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/network/bearer/qsharednetworksession.cpp b/src/network/bearer/qsharednetworksession.cpp index 28ca173..fcb0128 100644 --- a/src/network/bearer/qsharednetworksession.cpp +++ b/src/network/bearer/qsharednetworksession.cpp @@ -59,6 +59,11 @@ inline QSharedNetworkSessionManager* sharedNetworkSessionManager() return rv; } +static void doDeleteLater(QObject* obj) +{ + obj->deleteLater(); +} + QSharedPointer QSharedNetworkSessionManager::getSession(QNetworkConfiguration config) { QSharedNetworkSessionManager *m(sharedNetworkSessionManager()); @@ -69,7 +74,7 @@ QSharedPointer QSharedNetworkSessionManager::getSession(QNetwor return p; } //otherwise make one - QSharedPointer session(new QNetworkSession(config)); + QSharedPointer session(new QNetworkSession(config), doDeleteLater); m->sessions[config] = session; return session; } -- cgit v0.12 From 917a1a04d7a507dbab4ae9e9983507870232a821 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 28 Mar 2011 18:32:57 +0100 Subject: Make qhttpnetworkconnection autotest work with the new test server Loosen requirements for generated error pages (these vary with exact version and locale of the web server). Don't care what the length is, but if a content-length header is sent then it should match the size of the error page data. (apache2 does send content-length for errors) Don't fail the gzip test if the server doesn't send a content-length header. That's a server bug rather than Qt. (apache2 doesn't send) Reviewed-by: Markus Goetz --- .../tst_qhttpnetworkconnection.cpp | 48 ++++++++++++++-------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/tests/auto/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp b/tests/auto/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp index 0b72139..ba1f8c8 100644 --- a/tests/auto/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp +++ b/tests/auto/qhttpnetworkconnection/tst_qhttpnetworkconnection.cpp @@ -195,8 +195,8 @@ void tst_QHttpNetworkConnection::head() QCOMPARE(reply->statusCode(), statusCode); QCOMPARE(reply->reasonPhrase(), statusString); - // only check it if it is set - if (reply->contentLength() != -1) + // only check it if it is set and expected + if (reply->contentLength() != -1 && contentLength != -1) QCOMPARE(reply->contentLength(), qint64(contentLength)); QVERIFY(reply->isFinished()); @@ -219,8 +219,8 @@ void tst_QHttpNetworkConnection::get_data() QTest::newRow("success-internal") << "http://" << QtNetworkSettings::serverName() << "/qtest/rfc3252.txt" << ushort(80) << false << 200 << "OK" << 25962 << 25962; QTest::newRow("success-external") << "http://" << "www.ietf.org" << "/rfc/rfc3252.txt" << ushort(80) << false << 200 << "OK" << 25962 << 25962; - QTest::newRow("failure-path") << "http://" << QtNetworkSettings::serverName() << "/t" << ushort(80) << false << 404 << "Not Found" << -1 << 997 + QtNetworkSettings::serverName().size(); - QTest::newRow("failure-protocol") << "" << QtNetworkSettings::serverName() << "/qtest/rfc3252.txt" << ushort(80) << false << 400 << "Bad Request" << -1 << 930 + QtNetworkSettings::serverName().size(); + QTest::newRow("failure-path") << "http://" << QtNetworkSettings::serverName() << "/t" << ushort(80) << false << 404 << "Not Found" << -1 << -1; + QTest::newRow("failure-protocol") << "" << QtNetworkSettings::serverName() << "/qtest/rfc3252.txt" << ushort(80) << false << 400 << "Bad Request" << -1 << -1; } void tst_QHttpNetworkConnection::get() @@ -255,8 +255,8 @@ void tst_QHttpNetworkConnection::get() QCOMPARE(reply->statusCode(), statusCode); QCOMPARE(reply->reasonPhrase(), statusString); - // only check it if it is set - if (reply->contentLength() != -1) + // only check it if it is set and expected + if (reply->contentLength() != -1 && contentLength != -1) QCOMPARE(reply->contentLength(), qint64(contentLength)); stopWatch.start(); @@ -270,7 +270,12 @@ void tst_QHttpNetworkConnection::get() } while (!reply->isFinished()); QVERIFY(reply->isFinished()); - QCOMPARE(ba.size(), downloadSize); + //do not require server generated error pages to be a fixed size + if (downloadSize != -1) + QCOMPARE(ba.size(), downloadSize); + //but check against content length if it was sent + if (reply->contentLength() != -1) + QCOMPARE(ba.size(), (int)reply->contentLength()); delete reply; } @@ -385,7 +390,7 @@ void tst_QHttpNetworkConnection::post_data() QTest::addColumn("downloadSize"); QTest::newRow("success-internal") << "http://" << QtNetworkSettings::serverName() << "/qtest/cgi-bin/echo.cgi" << ushort(80) << false << "7 bytes" << 200 << "OK" << 7 << 7; - QTest::newRow("failure-internal") << "http://" << QtNetworkSettings::serverName() << "/t" << ushort(80) << false << "Hello World" << 404 << "Not Found" << -1 << 997 + QtNetworkSettings::serverName().size(); + QTest::newRow("failure-internal") << "http://" << QtNetworkSettings::serverName() << "/t" << ushort(80) << false << "Hello World" << 404 << "Not Found" << -1 << -1; } void tst_QHttpNetworkConnection::post() @@ -429,13 +434,16 @@ void tst_QHttpNetworkConnection::post() QCOMPARE(reply->reasonPhrase(), statusString); qint64 cLen = reply->contentLength(); - if (cLen==-1) { - // HTTP 1.1 server may respond with chunked encoding and in that - // case contentLength is not present in reply -> verify that it is the case - QByteArray transferEnc = reply->headerField("Transfer-Encoding"); - QCOMPARE(transferEnc, QByteArray("chunked")); - } else { - QCOMPARE(cLen, qint64(contentLength)); + if (contentLength != -1) { + // only check the content length if test expected it to be set + if (cLen==-1) { + // HTTP 1.1 server may respond with chunked encoding and in that + // case contentLength is not present in reply -> verify that it is the case + QByteArray transferEnc = reply->headerField("Transfer-Encoding"); + QCOMPARE(transferEnc, QByteArray("chunked")); + } else { + QCOMPARE(cLen, qint64(contentLength)); + } } stopWatch.start(); @@ -449,7 +457,12 @@ void tst_QHttpNetworkConnection::post() } while (!reply->isFinished()); QVERIFY(reply->isFinished()); - QCOMPARE(ba.size(), downloadSize); + //don't require fixed size for generated error pages + if (downloadSize != -1) + QCOMPARE(ba.size(), downloadSize); + //but do compare with content length if possible + if (cLen != -1) + QCOMPARE(ba.size(), (int)cLen); delete reply; } @@ -630,7 +643,8 @@ void tst_QHttpNetworkConnection::compression() QCOMPARE(reply->statusCode(), statusCode); QCOMPARE(reply->reasonPhrase(), statusString); bool isLengthOk = (reply->contentLength() == qint64(contentLength) - || reply->contentLength() == qint64(downloadSize)); + || reply->contentLength() == qint64(downloadSize) + || reply->contentLength() == -1); //apache2 does not send content-length for compressed pages QVERIFY(isLengthOk); -- cgit v0.12 From 8c3c9742abb2d59daa0b9f8f18bd52d9f2bbdbbe Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 28 Mar 2011 18:37:19 +0100 Subject: Add bearer startup to qabstractnetworkcache autotest This avoids the test starting and stopping the WLAN for each test case Reviewed-by: Markus Goetz --- .../tst_qabstractnetworkcache.cpp | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/auto/qabstractnetworkcache/tst_qabstractnetworkcache.cpp b/tests/auto/qabstractnetworkcache/tst_qabstractnetworkcache.cpp index db0d0a7..76e6711 100644 --- a/tests/auto/qabstractnetworkcache/tst_qabstractnetworkcache.cpp +++ b/tests/auto/qabstractnetworkcache/tst_qabstractnetworkcache.cpp @@ -45,6 +45,12 @@ #include "../../shared/util.h" #include "../network-settings.h" +#ifndef QT_NO_BEARERMANAGEMENT +#include +#include +#include +#endif + #define TESTFILE QString("http://%1/qtest/cgi-bin/").arg(QtNetworkSettings::serverName()) class tst_QAbstractNetworkCache : public QObject @@ -56,6 +62,7 @@ public: virtual ~tst_QAbstractNetworkCache(); private slots: + void initTestCase(); void expires_data(); void expires(); void expiresSynchronous_data(); @@ -81,6 +88,12 @@ private slots: private: void check(); void checkSynchronous(); + +#ifndef QT_NO_BEARERMANAGEMENT + QNetworkConfigurationManager *netConfMan; + QNetworkConfiguration networkConfiguration; + QScopedPointer networkSession; +#endif }; class NetworkDiskCache : public QNetworkDiskCache @@ -124,6 +137,19 @@ static bool AlwaysFalse = false; Q_DECLARE_METATYPE(QNetworkRequest::CacheLoadControl) +void tst_QAbstractNetworkCache::initTestCase() +{ +#ifndef QT_NO_BEARERMANAGEMENT + netConfMan = new QNetworkConfigurationManager(this); + networkConfiguration = netConfMan->defaultConfiguration(); + networkSession.reset(new QNetworkSession(networkConfiguration)); + if (!networkSession->isOpen()) { + networkSession->open(); + QVERIFY(networkSession->waitForOpened(30000)); + } +#endif +} + void tst_QAbstractNetworkCache::expires_data() { QTest::addColumn("cacheLoadControl"); -- cgit v0.12 From da83fb86defd4e9773d56640e87da32c1e8c7f82 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 28 Mar 2011 18:47:12 +0100 Subject: Remove 2 QSKIP from tst_qnetworkdiskcache Skipped because of open C bug, but these tests are passing in N8 with symbian socket & file engines Reviewed-by: Markus Goetz --- tests/auto/qnetworkdiskcache/tst_qnetworkdiskcache.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/auto/qnetworkdiskcache/tst_qnetworkdiskcache.cpp b/tests/auto/qnetworkdiskcache/tst_qnetworkdiskcache.cpp index e974fcc..9e06cc4 100644 --- a/tests/auto/qnetworkdiskcache/tst_qnetworkdiskcache.cpp +++ b/tests/auto/qnetworkdiskcache/tst_qnetworkdiskcache.cpp @@ -309,9 +309,6 @@ void tst_QNetworkDiskCache::data_data() // public QIODevice* data(QUrl const& url) void tst_QNetworkDiskCache::data() { -#ifdef Q_OS_SYMBIAN - QSKIP("Due to mmap(...) bug in Open C [Temtrack DEF142242]", SkipAll); -#endif QFETCH(QNetworkCacheMetaData, data); SubQNetworkDiskCache cache; QUrl url(EXAMPLE_URL); @@ -388,9 +385,6 @@ void tst_QNetworkDiskCache::setCacheDirectory() // public void updateMetaData(QNetworkCacheMetaData const& metaData) void tst_QNetworkDiskCache::updateMetaData() { -#ifdef Q_OS_SYMBIAN - QSKIP("Due to mmap(...) bug in Open C [Temtrack DEF142242]", SkipAll); -#endif QUrl url(EXAMPLE_URL); SubQNetworkDiskCache cache; cache.setupWithOne(url); -- cgit v0.12 From 2c09d9c463aeff4888e7b694351d15cbb760ccdf Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 28 Mar 2011 19:49:12 +0100 Subject: Fix ssl autotest .pro files ReadUserData needed to avoid platsec warnings accessing cert store. Removed incorrect deployment from the two new on demand tests. Reviewed-by: Markus Goetz --- tests/auto/qsslsocket/qsslsocket.pro | 2 +- .../qsslsocket_onDemandCertificates_member.pro | 10 +--------- .../qsslsocket_onDemandCertificates_static.pro | 10 +--------- 3 files changed, 3 insertions(+), 19 deletions(-) diff --git a/tests/auto/qsslsocket/qsslsocket.pro b/tests/auto/qsslsocket/qsslsocket.pro index 154f9ca..77517e0 100644 --- a/tests/auto/qsslsocket/qsslsocket.pro +++ b/tests/auto/qsslsocket/qsslsocket.pro @@ -24,7 +24,7 @@ wince* { } else:symbian { DEFINES += QSSLSOCKET_CERTUNTRUSTED_WORKAROUND TARGET.EPOCHEAPSIZE="0x100 0x3000000" - TARGET.CAPABILITY=NetworkServices + TARGET.CAPABILITY=NetworkServices ReadUserData certFiles.files = certs ssl.tar.gz certFiles.path = . diff --git a/tests/auto/qsslsocket_onDemandCertificates_member/qsslsocket_onDemandCertificates_member.pro b/tests/auto/qsslsocket_onDemandCertificates_member/qsslsocket_onDemandCertificates_member.pro index ea62865..53020eb 100644 --- a/tests/auto/qsslsocket_onDemandCertificates_member/qsslsocket_onDemandCertificates_member.pro +++ b/tests/auto/qsslsocket_onDemandCertificates_member/qsslsocket_onDemandCertificates_member.pro @@ -17,17 +17,9 @@ win32 { wince* { DEFINES += SRCDIR=\\\"./\\\" - - certFiles.files = certs ssl.tar.gz - certFiles.path = . - DEPLOYMENT += certFiles } else:symbian { TARGET.EPOCHEAPSIZE="0x100 0x1000000" - TARGET.CAPABILITY=NetworkServices - - certFiles.files = certs ssl.tar.gz - certFiles.path = . - DEPLOYMENT += certFiles + TARGET.CAPABILITY=NetworkServices ReadUserData INCLUDEPATH *= $$MW_LAYER_SYSTEMINCLUDE # Needed for e32svr.h in S^3 envs } else { DEFINES += SRCDIR=\\\"$$PWD/\\\" diff --git a/tests/auto/qsslsocket_onDemandCertificates_static/qsslsocket_onDemandCertificates_static.pro b/tests/auto/qsslsocket_onDemandCertificates_static/qsslsocket_onDemandCertificates_static.pro index 13990cb..3452a92 100644 --- a/tests/auto/qsslsocket_onDemandCertificates_static/qsslsocket_onDemandCertificates_static.pro +++ b/tests/auto/qsslsocket_onDemandCertificates_static/qsslsocket_onDemandCertificates_static.pro @@ -17,17 +17,9 @@ win32 { wince* { DEFINES += SRCDIR=\\\"./\\\" - - certFiles.files = certs ssl.tar.gz - certFiles.path = . - DEPLOYMENT += certFiles } else:symbian { TARGET.EPOCHEAPSIZE="0x100 0x1000000" - TARGET.CAPABILITY=NetworkServices - - certFiles.files = certs ssl.tar.gz - certFiles.path = . - DEPLOYMENT += certFiles + TARGET.CAPABILITY=NetworkServices ReadUserData INCLUDEPATH *= $$MW_LAYER_SYSTEMINCLUDE # Needed for e32svr.h in S^3 envs } else { DEFINES += SRCDIR=\\\"$$PWD/\\\" -- cgit v0.12 From 6022cd668435d1dda127e26e71de01982c7441a3 Mon Sep 17 00:00:00 2001 From: Aaron Tunney Date: Wed, 30 Mar 2011 16:46:10 +0100 Subject: Ayschronous Next() change for DNS resolution. Reviewed-By: Shane Kearns --- src/network/kernel/qhostinfo_p.h | 12 +++- src/network/kernel/qhostinfo_symbian.cpp | 116 ++++++++++++++++++------------- 2 files changed, 77 insertions(+), 51 deletions(-) diff --git a/src/network/kernel/qhostinfo_p.h b/src/network/kernel/qhostinfo_p.h index a7e83da..ab3e809 100644 --- a/src/network/kernel/qhostinfo_p.h +++ b/src/network/kernel/qhostinfo_p.h @@ -236,6 +236,8 @@ public: void requestHostLookup(); int id(); + void returnResults(); + QHostInfoResult resultEmitter; private: @@ -244,10 +246,13 @@ private: void run(); TInt RunError(TInt aError); - void processNameResults(); - void processAddressResults(); + void processNameResult(); + void nextNameResult(); + void processAddressResult(); private: + int iId; + const QString iHostName; QString iEncodedHostName; TPtrC iHostNamePtr; @@ -263,10 +268,13 @@ private: QHostInfo iResults; + QList iHostAddresses; + enum { EIdle, EGetByName, EGetByAddress, + EGetMoreNames, EError } iState; }; diff --git a/src/network/kernel/qhostinfo_symbian.cpp b/src/network/kernel/qhostinfo_symbian.cpp index 02bef40..70ee5b8 100644 --- a/src/network/kernel/qhostinfo_symbian.cpp +++ b/src/network/kernel/qhostinfo_symbian.cpp @@ -53,9 +53,12 @@ #include #include -QT_BEGIN_NAMESPACE - +// Header does not exist in the S60 5.0 SDK +//#include +const TInt KErrDndNameNotFound = -5120; // Returned when no data found for GetByName +const TInt KErrDndAddrNotFound = -5121; // Returned when no data found for GetByAddr +QT_BEGIN_NAMESPACE QHostInfo QHostInfoAgent::fromName(const QString &hostName, QSharedPointer networkSession) { @@ -88,15 +91,14 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName, QSharedPointer 0)) { + if (!(nameResult().iFlags & TNameRecord::EAlias) && !(hostAdd.IsUnspecified())) { hostAddresses.append(QHostAddress(qt_TDesC2QString(ipAddr))); } } @@ -244,7 +246,6 @@ void QSymbianHostResolver::requestHostLookup() #endif } if (err) { - // What are we doing with iResults?? iResults.setError(QHostInfo::UnknownError); iResults.setErrorString(QSystemError(err, QSystemError::NativeError).toString()); @@ -252,7 +253,6 @@ void QSymbianHostResolver::requestHostLookup() if (iAddress.setAddress(iHostName)) { // Reverse lookup - IpAdd.Input(qt_QString2TPtrC(iHostName)); // Asynchronous request. @@ -297,7 +297,7 @@ void QSymbianHostResolver::DoCancel() #if defined(QHOSTINFO_DEBUG) qDebug() << "QSymbianHostResolver::DoCancel" << QThread::currentThreadId() << id() << (int)iState << this; #endif - if (iState == EGetByAddress || iState == EGetByName) { + if (iState == EGetByAddress || iState == EGetByName || iState == EGetMoreNames) { //these states have made an async request to host resolver iHostResolver.Cancel(); } else { @@ -313,11 +313,25 @@ void QSymbianHostResolver::RunL() void QSymbianHostResolver::run() { - if (iState == EGetByName) - processNameResults(); - else if (iState == EGetByAddress) - processAddressResults(); + switch (iState) { + case EGetByName: + processNameResult(); + break; + case EGetByAddress: + processAddressResult(); + break; + case EError: + returnResults(); + break; + default: + iResults.setError(QHostInfo::UnknownError); + iResults.setErrorString(QSystemError(KErrCorrupt,QSystemError::NativeError).toString()); + returnResults(); + } +} +void QSymbianHostResolver::returnResults() +{ iState = EIdle; QSymbianHostInfoLookupManger *manager = QSymbianHostInfoLookupManger::globalInstance(); @@ -348,55 +362,57 @@ TInt QSymbianHostResolver::RunError(TInt aError) return KErrNone; } -void QSymbianHostResolver::processNameResults() +void QSymbianHostResolver::processNameResult() { - TInt err = iStatus.Int(); - if (err < 0) { - // TODO - Could there be other errors? Symbian docs don't say. - if (err == KErrNotFound) { - iResults.setError(QHostInfo::HostNotFound); - iResults.setErrorString(QObject::tr("Host not found")); - } else { - iResults.setError(QHostInfo::UnknownError); - iResults.setErrorString(QSystemError(err,QSystemError::NativeError).toString()); - } - - iHostResolver.Close(); - return; - } - - QList hostAddresses; - - TInetAddr hostAdd = iNameResult().iAddr; - // 39 is the maximum length of an IPv6 address. - TBuf<39> ipAddr; - - // Fill ipAddr with the IP address from hostAdd - hostAdd.Output(ipAddr); - if (ipAddr.Length() > 0) - hostAddresses.append(QHostAddress(qt_TDesC2QString(ipAddr))); + if (iStatus.Int() == KErrNone) { + TInetAddr hostAdd = iNameResult().iAddr; + // 39 is the maximum length of an IPv6 address. + TBuf<39> ipAddr; - // Check if there's more than one IP address linkd to this name - while (iHostResolver.Next(iNameResult) == KErrNone) { - hostAdd = iNameResult().iAddr; hostAdd.Output(ipAddr); // Ensure that record is valid (not an alias and with length greater than 0) - if (!(iNameResult().iFlags & TNameRecord::EAlias) && (ipAddr.Length() > 0)) { - hostAddresses.append(QHostAddress(qt_TDesC2QString(ipAddr))); + if (!(iNameResult().iFlags & TNameRecord::EAlias) && !(hostAdd.IsUnspecified())) { + if (iNameResult().iAddr.Family() == KAfInet) { + // IPv4 - prepend + iHostAddresses.prepend(QHostAddress(qt_TDesC2QString(ipAddr))); + } else { + // IPv6 - append + iHostAddresses.append(QHostAddress(qt_TDesC2QString(ipAddr))); + } } - } - iResults.setAddresses(hostAddresses); + iState = EGetByName; + iHostResolver.Next(iNameResult, iStatus); + SetActive(); + } + else if (iStatus.Int() == KErrDndNameNotFound) { + // No more addresses, so return the results (or an error if there aren't any). + if (iHostAddresses.count() > 0) { + iResults.setAddresses(iHostAddresses); + } else { + iState = EError; + iResults.setError(QHostInfo::HostNotFound); + iResults.setErrorString(QObject::tr("Host not found")); + } + returnResults(); + } + else { + // Unknown error + iState = EError; + iResults.setError(QHostInfo::UnknownError); + iResults.setErrorString(QSystemError(iStatus.Int(),QSystemError::NativeError).toString()); + returnResults(); + } } -void QSymbianHostResolver::processAddressResults() +void QSymbianHostResolver::processAddressResult() { TInt err = iStatus.Int(); if (err < 0) { // TODO - Could there be other errors? Symbian docs don't say. - if (err == KErrNotFound) { + if (err == KErrDndAddrNotFound) { iResults.setError(QHostInfo::HostNotFound); iResults.setErrorString(QObject::tr("Host not found")); } else { @@ -404,11 +420,13 @@ void QSymbianHostResolver::processAddressResults() iResults.setErrorString(QSystemError(err,QSystemError::NativeError).toString()); } + returnResults(); return; } iResults.setHostName(qt_TDesC2QString(iNameResult().iName)); iResults.setAddresses(QList() << iAddress); + returnResults(); } -- cgit v0.12 From 591081142ce34435b4935d048a392c5727484c16 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Thu, 31 Mar 2011 15:37:13 +0100 Subject: Fix error handling in qhostinfo_symbian De-duplicate error handling into a helper function. RHostResolver can return a few different errors at the end of the list, so treat these benign ones the same. When Next() gives an error, return any results we already obtained. Reviewed-by: Aaron Tunney --- src/network/kernel/qhostinfo_symbian.cpp | 96 ++++++++++++++------------------ 1 file changed, 42 insertions(+), 54 deletions(-) diff --git a/src/network/kernel/qhostinfo_symbian.cpp b/src/network/kernel/qhostinfo_symbian.cpp index 70ee5b8..73fed16 100644 --- a/src/network/kernel/qhostinfo_symbian.cpp +++ b/src/network/kernel/qhostinfo_symbian.cpp @@ -60,6 +60,25 @@ const TInt KErrDndAddrNotFound = -5121; // Returned when no data found for GetBy QT_BEGIN_NAMESPACE +static void setError_helper(QHostInfo &info, TInt symbianError) +{ + switch (symbianError) { + case KErrDndNameNotFound: + case KErrDndAddrNotFound: + case KErrNotFound: + case KErrEof: + // various "no more results" error codes + info.setError(QHostInfo::HostNotFound); + info.setErrorString(QObject::tr("Host not found")); + break; + default: + // Unknown error + info.setError(QHostInfo::UnknownError); + info.setErrorString(QSystemError(symbianError, QSystemError::NativeError).toString()); + break; + } +} + QHostInfo QHostInfoAgent::fromName(const QString &hostName, QSharedPointer networkSession) { QHostInfo results; @@ -75,9 +94,7 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName, QSharedPointer() << address); } - - results.setHostName(qt_TDesC2QString(nameResult().iName)); - results.setAddresses(QList() << address); return results; } @@ -132,15 +140,7 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName, QSharedPointerlookupFinished(this); - iResults.setError(QHostInfo::UnknownError); - iResults.setErrorString(QSystemError(aError,QSystemError::NativeError).toString()); + setError_helper(iResults, aError); resultEmitter.emitResultsReady(iResults); } @@ -386,24 +389,19 @@ void QSymbianHostResolver::processNameResult() iHostResolver.Next(iNameResult, iStatus); SetActive(); } - else if (iStatus.Int() == KErrDndNameNotFound) { + else { // No more addresses, so return the results (or an error if there aren't any). +#if defined(QHOSTINFO_DEBUG) + qDebug() << "QSymbianHostResolver::processNameResult with err=" << iStatus.Int() << "count=" << iHostAddresses.count(); +#endif if (iHostAddresses.count() > 0) { iResults.setAddresses(iHostAddresses); } else { iState = EError; - iResults.setError(QHostInfo::HostNotFound); - iResults.setErrorString(QObject::tr("Host not found")); + setError_helper(iResults, iStatus.Int()); } returnResults(); } - else { - // Unknown error - iState = EError; - iResults.setError(QHostInfo::UnknownError); - iResults.setErrorString(QSystemError(iStatus.Int(),QSystemError::NativeError).toString()); - returnResults(); - } } void QSymbianHostResolver::processAddressResult() @@ -411,21 +409,11 @@ void QSymbianHostResolver::processAddressResult() TInt err = iStatus.Int(); if (err < 0) { - // TODO - Could there be other errors? Symbian docs don't say. - if (err == KErrDndAddrNotFound) { - iResults.setError(QHostInfo::HostNotFound); - iResults.setErrorString(QObject::tr("Host not found")); - } else { - iResults.setError(QHostInfo::UnknownError); - iResults.setErrorString(QSystemError(err,QSystemError::NativeError).toString()); - } - - returnResults(); - return; + setError_helper(iResults, err); + } else { + iResults.setHostName(qt_TDesC2QString(iNameResult().iName)); + iResults.setAddresses(QList() << iAddress); } - - iResults.setHostName(qt_TDesC2QString(iNameResult().iName)); - iResults.setAddresses(QList() << iAddress); returnResults(); } -- cgit v0.12 From 00121f3184ade624ca9cbb2524222dcab9f67342 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 29 Mar 2011 11:55:58 +0100 Subject: Add partial upgrade rules for Qt's plugins Allows testing of plugins such as bearer without needing to reinstall all of Qt. Equivalent to the rules in qbase.pri for the normal DLLs Reviewed-by: Miikka Heikkinen --- src/plugins/qpluginbase.pri | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/plugins/qpluginbase.pri b/src/plugins/qpluginbase.pri index 45e3976..bcf473f 100644 --- a/src/plugins/qpluginbase.pri +++ b/src/plugins/qpluginbase.pri @@ -19,4 +19,23 @@ symbian: { TARGET.CAPABILITY = All -Tcb TARGET = $${TARGET}$${QT_LIBINFIX} load(armcc_warnings) + + # Make partial upgrade SIS file for Qt plugin dll's + # Partial upgrade SIS file + vendorinfo = \ + "; Localised Vendor name" \ + "%{\"Nokia\"}" \ + " " \ + "; Unique Vendor name" \ + ":\"Nokia, Qt\"" \ + " " + isEmpty(QT_LIBINFIX): PARTIAL_UPGRADE_UID = 0x2001E61C + else: PARTIAL_UPGRADE_UID = 0xE001E61C + + pu_header = "; Partial upgrade package for testing $${TARGET} changes without reinstalling everything" \ + "$${LITERAL_HASH}{\"$${TARGET}\"}, ($$PARTIAL_UPGRADE_UID), $${QT_MAJOR_VERSION},$${QT_MINOR_VERSION},$${QT_PATCH_VERSION}, TYPE=PU" + partial_upgrade.pkg_prerules = pu_header vendorinfo + partial_upgrade.files = $$QMAKE_LIBDIR_QT/$${TARGET}.dll + partial_upgrade.path = c:/sys/bin + DEPLOYMENT += partial_upgrade } -- cgit v0.12 From f7a6e37cab7a68451b176d22acf34ed41d4f1d79 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 29 Mar 2011 11:58:32 +0100 Subject: Fix deadlock in QNetworkSession::stop The mutex added needs to be recursive, as stop calls close internally, which also needs to lock the mutex. Reviewed-by: Markus Goetz --- src/network/bearer/qnetworksession_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/bearer/qnetworksession_p.h b/src/network/bearer/qnetworksession_p.h index b359f80..a92b7ce 100644 --- a/src/network/bearer/qnetworksession_p.h +++ b/src/network/bearer/qnetworksession_p.h @@ -75,7 +75,7 @@ class Q_NETWORK_EXPORT QNetworkSessionPrivate : public QObject public: QNetworkSessionPrivate() : QObject(), - state(QNetworkSession::Invalid), isOpen(false) + state(QNetworkSession::Invalid), isOpen(false), mutex(QMutex::Recursive) {} virtual ~QNetworkSessionPrivate() {} -- cgit v0.12 From e1f5699f262d52e72d6855440cfc1c2919b74163 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Wed, 30 Mar 2011 16:39:14 +0100 Subject: Don't reinitialise udp socket when IP versions don't match An IPv6 socket can send to IPv4 addresses when in a dual mode stack. On symbian, autobinded sockets have the ::0 local address rather than 0.0.0.0 - this check was causing the socket to be destroyed and recreated with every call to writeDatagram. Reviewed-by: Markus Goetz --- src/network/socket/qudpsocket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/socket/qudpsocket.cpp b/src/network/socket/qudpsocket.cpp index 4334f68..dc473c6 100644 --- a/src/network/socket/qudpsocket.cpp +++ b/src/network/socket/qudpsocket.cpp @@ -202,7 +202,7 @@ bool QUdpSocketPrivate::doEnsureInitialized(const QHostAddress &bindAddress, qui #endif // now check if the socket engine is initialized and to the right type - if (!socketEngine || !socketEngine->isValid() || socketEngine->protocol() != proto) { + if (!socketEngine || !socketEngine->isValid()) { resolveProxy(remoteAddress.toString(), bindPort); if (!initSocketLayer(address->protocol())) return false; -- cgit v0.12 From 989ca02a932cf7c90e8d29c18dd72415e46afb81 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Wed, 30 Mar 2011 16:48:51 +0100 Subject: Fix assert fail when debug log is enabled Enough debug logging allows time for the proxy server to close the http connection after sending a 407 response. This errors the connection, but then the queued _q_startNextRequest is immediately run, causing an assertion failure. Changed this to a soft failure which allows the error to propagate rather than crashing. Test case is tst_qnetworkreply::ioPostToHttpFromSocket Reviewed-by: Markus Goetz --- src/network/access/qhttpnetworkconnectionchannel.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp index a6d6172..6fbc6f8 100644 --- a/src/network/access/qhttpnetworkconnectionchannel.cpp +++ b/src/network/access/qhttpnetworkconnectionchannel.cpp @@ -842,7 +842,10 @@ void QHttpNetworkConnectionChannel::handleStatus() bool QHttpNetworkConnectionChannel::resetUploadData() { - Q_ASSERT(reply); + if (!reply) { + //this happens if server closes connection while QHttpNetworkConnectionPrivate::_q_startNextRequest is pending + return false; + } QNonContiguousByteDevice* uploadByteDevice = request.uploadByteDevice(); if (!uploadByteDevice) return true; -- cgit v0.12 From cd907ff4656c8819f5aa19979ea6da25fc5947e6 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Wed, 30 Mar 2011 17:06:07 +0100 Subject: Fix multicast group membership Although symbian's multicast support is incomplete, this is enough to pass the QUdpSocket test case. (no IGMP/MLD support in the OS) Reviewed-by: Markus Goetz --- src/network/socket/qsymbiansocketengine.cpp | 36 ++++++++++++++++++----------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index af755a9..52f6b68 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -1198,22 +1198,32 @@ bool QSymbianSocketEnginePrivate::multicastGroupMembershipHelper(const QHostAddr const QNetworkInterface &iface, TUint operation) { - //TODO - untested +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug() << "QSymbianSocketEnginePrivate::multicastGroupMembershipHelper" << groupAddress << iface << operation; +#endif //translate address TPckgBuf option; - Q_IPV6ADDR ip6 = groupAddress.toIPv6Address(); - memcpy(option().iAddr.u.iAddr8, ip6.c, 16); - //translate interface - //TODO - can we just use iface.index() ? - TPckgBuf query; - query().iName = qt_QString2TPtrC(iface.name()); - TInt err = nativeSocket.GetOpt(KSoInetIfQueryByName, KSolInetIfQuery, query); - if (err == KErrNone) - option().iInterface = query().iIndex; - else - option().iInterface = 0; + if (groupAddress.protocol() == QAbstractSocket::IPv6Protocol) { + Q_IPV6ADDR ip6 = groupAddress.toIPv6Address(); + memcpy(option().iAddr.u.iAddr8, ip6.c, 16); + } else { + TInetAddr wrapped; + wrapped.SetAddress(groupAddress.toIPv4Address()); + wrapped.ConvertToV4Mapped(); + option().iAddr = wrapped.Ip6Address(); + } + option().iInterface = iface.index(); //join or leave group - return (KErrNone == nativeSocket.SetOpt(operation, KSolInetIp, option)); + TInt err = nativeSocket.SetOpt(operation, KSolInetIp, option); +#if defined (QNATIVESOCKETENGINE_DEBUG) + qDebug() << "address" << qt_prettyDebug((const char *)(option().iAddr.u.iAddr8), 16, 16); + qDebug() << "interface" << option().iInterface; + qDebug() << "error" << err; +#endif + if (err) { + setError(err); + } + return (KErrNone == err); } QNetworkInterface QSymbianSocketEngine::multicastInterface() const -- cgit v0.12 From 1d8f8bc70e4f056e4e110a779d483c186fc2ad19 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Thu, 31 Mar 2011 12:19:45 +0100 Subject: Update address reporting code When an IP6 address contains a valid IP4 address, report the address in IP4 format (this is needed for SOCKS5 socket engine) When binding Any or AnyIPv6, create a dual mode socket (KAfUnspec), but report the local address as being the same as what the user requested. (by default, symbian returns ::0 for the dual mode socket, which causes problems for SOCKS and UDP code) The intent is that most applications written for IP4 can work transparently in an IP6 environment. QTcpServer or QUdpSocket can accept either IP4 or IP6 from the same socket. Reviewed-by: Markus Goetz --- src/network/socket/qsymbiansocketengine.cpp | 39 +++++++++++++---------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index 52f6b68..165316d 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -147,7 +147,7 @@ static QByteArray qt_prettyDebug(const char *data, int len, int maxSize) void QSymbianSocketEnginePrivate::getPortAndAddress(const TInetAddr& a, quint16 *port, QHostAddress *addr) { - if (a.Family() == KAfInet6) { + if (a.Family() == KAfInet6 && !a.IsV4Compat() && !a.IsV4Mapped()) { Q_IPV6ADDR tmp; memcpy(&tmp, a.Ip6Address().u.iAddr8, sizeof(tmp)); if (addr) { @@ -226,12 +226,7 @@ bool QSymbianSocketEnginePrivate::createNewSocket(QAbstractSocket::SocketType so void QSymbianSocketEnginePrivate::setPortAndAddress(TInetAddr& nativeAddr, quint16 port, const QHostAddress &addr) { nativeAddr.SetPort(port); - if (addr == QHostAddress::Any) { - //Should allow both IPv4 and IPv6 - //Listening on "0.0.0.0" accepts ONLY ipv4 connections - //Listening on "::" accepts ONLY ipv6 connections - nativeAddr.SetFamily(KAFUnspec); - } else if (addr.protocol() == QAbstractSocket::IPv6Protocol) { + if (addr.protocol() == QAbstractSocket::IPv6Protocol) { TPckgBuf query; query().iName = qt_QString2TPtrC(addr.scopeId()); TInt err = nativeSocket.GetOpt(KSoInetIfQueryByName, KSolInetIfQuery, query); @@ -274,7 +269,6 @@ QSymbianSocketEngine::QSymbianSocketEngine(QObject *parent) QSymbianSocketEngine::~QSymbianSocketEngine() { close(); - // FIXME what else do we need to free? } /*! @@ -650,7 +644,15 @@ bool QSymbianSocketEngine::bind(const QHostAddress &address, quint16 port) Q_CHECK_STATE(QSymbianSocketEngine::bind(), QAbstractSocket::UnconnectedState, false); TInetAddr nativeAddr; - d->setPortAndAddress(nativeAddr, port, address); + if (address == QHostAddress::Any || address == QHostAddress::AnyIPv6) { + //Should allow both IPv4 and IPv6 + //Listening on "0.0.0.0" accepts ONLY ipv4 connections + //Listening on "::" accepts ONLY ipv6 connections + nativeAddr.SetFamily(KAFUnspec); + nativeAddr.SetPort(port); + } else { + d->setPortAndAddress(nativeAddr, port, address); + } TInt err = d->nativeSocket.Bind(nativeAddr); #ifdef __WINS__ @@ -684,6 +686,11 @@ bool QSymbianSocketEngine::bind(const QHostAddress &address, quint16 port) d->socketState = QAbstractSocket::BoundState; d->fetchConnectionParameters(); + + // When we bind to unspecified address (to get a dual mode socket), report back the + // same type of address that was requested. This is required for SOCKS proxy to work. + if (nativeAddr.Family() == KAFUnspec) + d->localAddress = address; return true; } @@ -693,8 +700,6 @@ bool QSymbianSocketEngine::listen() Q_CHECK_VALID_SOCKETLAYER(QSymbianSocketEngine::listen(), false); Q_CHECK_STATE(QSymbianSocketEngine::listen(), QAbstractSocket::BoundState, false); Q_CHECK_TYPE(QSymbianSocketEngine::listen(), QAbstractSocket::TcpSocket, false); - // TODO the value 50 is from the QNativeSocketEngine. Maybe it's a bit too much - // for a mobile platform TInt err = d->nativeSocket.Listen(50); if (err) { d->setError(err); @@ -898,17 +903,7 @@ bool QSymbianSocketEnginePrivate::fetchConnectionParameters() getPortAndAddress(addr, &localPort, &localAddress); // Determine protocol family - switch (addr.Family()) { - case KAfInet: - socketProtocol = QAbstractSocket::IPv4Protocol; - break; - case KAfInet6: - socketProtocol = QAbstractSocket::IPv6Protocol; - break; - default: - socketProtocol = QAbstractSocket::UnknownNetworkLayerProtocol; - break; - } + socketProtocol = localAddress.protocol(); // Determine the remote address nativeSocket.RemoteName(addr); -- cgit v0.12 From a04905c2bb5caac9c9c0a3d0928f6fdfb4600cb9 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Fri, 1 Apr 2011 11:08:39 +0100 Subject: Implement cache support for the async resolver Add additional check when starting a queued request, as the cache may have been populated while the request was queued. Put completed requests in the cache (note cache code internally discards errored results and only caches successful results) Reviewed-by: Aaron Tunney Reviewed-by: Markus Goetz --- src/network/kernel/qhostinfo_p.h | 2 +- src/network/kernel/qhostinfo_symbian.cpp | 29 +++++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/network/kernel/qhostinfo_p.h b/src/network/kernel/qhostinfo_p.h index ab3e809..ceec04d 100644 --- a/src/network/kernel/qhostinfo_p.h +++ b/src/network/kernel/qhostinfo_p.h @@ -274,7 +274,7 @@ private: EIdle, EGetByName, EGetByAddress, - EGetMoreNames, + ECompleteFromCache, EError } iState; }; diff --git a/src/network/kernel/qhostinfo_symbian.cpp b/src/network/kernel/qhostinfo_symbian.cpp index 73fed16..a38a845 100644 --- a/src/network/kernel/qhostinfo_symbian.cpp +++ b/src/network/kernel/qhostinfo_symbian.cpp @@ -108,6 +108,9 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName, QSharedPointercache.isEnabled()) { + //check if name has been put in the cache while this request was queued + bool valid; + QHostInfo cachedResult = manager->cache.get(iHostName, &valid); + if (valid) { +#if defined(QHOSTINFO_DEBUG) + qDebug("...found in cache"); +#endif + iResults = cachedResult; + iState = ECompleteFromCache; + SetActive(); + TRequestStatus* stat = &iStatus; + User::RequestComplete(stat, KErrNone); + return; + } + } + int err; if (iNetworkSession) { err = QNetworkSessionPrivate::nativeOpenHostResolver(*iNetworkSession, iHostResolver, KAfInet, KProtocolInetUdp); @@ -295,12 +316,12 @@ void QSymbianHostResolver::DoCancel() #if defined(QHOSTINFO_DEBUG) qDebug() << "QSymbianHostResolver::DoCancel" << QThread::currentThreadId() << id() << (int)iState << this; #endif - if (iState == EGetByAddress || iState == EGetByName || iState == EGetMoreNames) { + if (iState == EGetByAddress || iState == EGetByName) { //these states have made an async request to host resolver iHostResolver.Cancel(); } else { //for the self completing states there is nothing to cancel - Q_ASSERT(iState == EError); + Q_ASSERT(iState == EError || iState == ECompleteFromCache); } } @@ -318,6 +339,7 @@ void QSymbianHostResolver::run() case EGetByAddress: processAddressResult(); break; + case ECompleteFromCache: case EError: returnResults(); break; @@ -339,6 +361,9 @@ void QSymbianHostResolver::returnResults() iState = EIdle; QSymbianHostInfoLookupManger *manager = QSymbianHostInfoLookupManger::globalInstance(); + if (manager->cache.isEnabled()) { + manager->cache.put(iHostName, iResults); + } manager->lookupFinished(this); resultEmitter.emitResultsReady(iResults); -- cgit v0.12 From 108dbea7145c941ba39f3958596cd1f348a2a049 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 4 Apr 2011 17:32:20 +0100 Subject: Add test case for thread safety of the QHostInfo async API The existing threadSafety test only tested calling the blocking API from multiple threads. As the asynchronous API may be implemented in a different way, it should be tested separately. Create 10 threads, each of which queues 10 async name lookups. Reviewed-by: Markus Goetz --- tests/auto/qhostinfo/tst_qhostinfo.cpp | 53 +++++++++++++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/tests/auto/qhostinfo/tst_qhostinfo.cpp b/tests/auto/qhostinfo/tst_qhostinfo.cpp index 8be8dcb..7b2fc55 100644 --- a/tests/auto/qhostinfo/tst_qhostinfo.cpp +++ b/tests/auto/qhostinfo/tst_qhostinfo.cpp @@ -126,6 +126,7 @@ private slots: void raceCondition(); void threadSafety(); + void threadSafetyAsynchronousAPI(); void multipleSameLookups(); void multipleDifferentLookups_data(); @@ -419,7 +420,7 @@ protected: void tst_QHostInfo::threadSafety() { const int nattempts = 5; -#if defined(Q_OS_WINCE) +#if defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN) const int runs = 10; #else const int runs = 100; @@ -433,6 +434,56 @@ void tst_QHostInfo::threadSafety() } } +class LookupReceiver : public QObject +{ + Q_OBJECT +public slots: + void start(); + void resultsReady(const QHostInfo&); +public: + QHostInfo result; + int numrequests; +}; + +void LookupReceiver::start() +{ + for (int i=0;iquit(); +} + +void tst_QHostInfo::threadSafetyAsynchronousAPI() +{ + const int nattempts = 10; + const int lookupsperthread = 10; + QList threads; + QList receivers; + for (int i = 0; i < nattempts; ++i) { + QThread* thread = new QThread; + LookupReceiver* receiver = new LookupReceiver; + receiver->numrequests = lookupsperthread; + receivers.append(receiver); + receiver->moveToThread(thread); + connect(thread, SIGNAL(started()), receiver, SLOT(start())); + thread->start(); + threads.append(thread); + } + for (int k = threads.count() - 1; k >= 0; --k) + QVERIFY(threads.at(k)->wait(60000)); + foreach (LookupReceiver* receiver, receivers) { + QCOMPARE(receiver->result.error(), QHostInfo::NoError); + QCOMPARE(receiver->result.addresses().at(0).toString(), QString("87.238.50.178")); + QCOMPARE(receiver->numrequests, 0); + } +} + // this test is for the multi-threaded QHostInfo rewrite. It is about getting results at all, // not about getting correct IPs void tst_QHostInfo::multipleSameLookups() -- cgit v0.12 From 3b395c6e45ed4f73503586e6b9a80bb11844d315 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 4 Apr 2011 17:48:27 +0100 Subject: Fix typo in class name Manger -> Manager Reviewed-by: Markus Goetz --- src/network/kernel/qhostinfo.cpp | 16 +++++++------- src/network/kernel/qhostinfo_p.h | 18 +++++++-------- src/network/kernel/qhostinfo_symbian.cpp | 38 ++++++++++++++++---------------- 3 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/network/kernel/qhostinfo.cpp b/src/network/kernel/qhostinfo.cpp index 3413c9b..a16d4ca 100644 --- a/src/network/kernel/qhostinfo.cpp +++ b/src/network/kernel/qhostinfo.cpp @@ -62,7 +62,7 @@ QT_BEGIN_NAMESPACE #ifndef Q_OS_SYMBIAN Q_GLOBAL_STATIC(QHostInfoLookupManager, theHostInfoLookupManager) #else -Q_GLOBAL_STATIC(QSymbianHostInfoLookupManger, theHostInfoLookupManager) +Q_GLOBAL_STATIC(QSymbianHostInfoLookupManager, theHostInfoLookupManager) #endif /*! @@ -202,7 +202,7 @@ int QHostInfo::lookupHost(const QString &name, QObject *receiver, manager->scheduleLookup(runnable); } #else - QSymbianHostInfoLookupManger *manager = theHostInfoLookupManager(); + QSymbianHostInfoLookupManager *manager = theHostInfoLookupManager(); if (manager) { // the application is still alive @@ -267,7 +267,7 @@ QHostInfo QHostInfo::fromName(const QString &name) #endif QHostInfo hostInfo = QHostInfoAgent::fromName(name); - QAbstractHostInfoLookupManger* manager = theHostInfoLookupManager(); + QAbstractHostInfoLookupManager* manager = theHostInfoLookupManager(); manager->cache.put(name, hostInfo); return hostInfo; } @@ -280,7 +280,7 @@ QHostInfo QHostInfoPrivate::fromName(const QString &name, QSharedPointercache.put(name, hostInfo); return hostInfo; } @@ -707,7 +707,7 @@ QHostInfo qt_qhostinfo_lookup(const QString &name, QObject *receiver, const char *id = -1; // check cache - QAbstractHostInfoLookupManger* manager = theHostInfoLookupManager(); + QAbstractHostInfoLookupManager* manager = theHostInfoLookupManager(); if (manager && manager->cache.isEnabled()) { QHostInfo info = manager->cache.get(name, valid); if (*valid) { @@ -724,7 +724,7 @@ QHostInfo qt_qhostinfo_lookup(const QString &name, QObject *receiver, const char void qt_qhostinfo_clear_cache() { - QAbstractHostInfoLookupManger* manager = theHostInfoLookupManager(); + QAbstractHostInfoLookupManager* manager = theHostInfoLookupManager(); if (manager) { manager->clear(); } @@ -732,7 +732,7 @@ void qt_qhostinfo_clear_cache() void Q_AUTOTEST_EXPORT qt_qhostinfo_enable_cache(bool e) { - QAbstractHostInfoLookupManger* manager = theHostInfoLookupManager(); + QAbstractHostInfoLookupManager* manager = theHostInfoLookupManager(); if (manager) { manager->cache.setEnabled(e); } @@ -800,7 +800,7 @@ void QHostInfoCache::clear() cache.clear(); } -QAbstractHostInfoLookupManger* QAbstractHostInfoLookupManger::globalInstance() +QAbstractHostInfoLookupManager* QAbstractHostInfoLookupManager::globalInstance() { return theHostInfoLookupManager(); } diff --git a/src/network/kernel/qhostinfo_p.h b/src/network/kernel/qhostinfo_p.h index ceec04d..bae6efa 100644 --- a/src/network/kernel/qhostinfo_p.h +++ b/src/network/kernel/qhostinfo_p.h @@ -172,24 +172,24 @@ public: }; -class QAbstractHostInfoLookupManger : public QObject +class QAbstractHostInfoLookupManager : public QObject { Q_OBJECT public: - ~QAbstractHostInfoLookupManger() {} + ~QAbstractHostInfoLookupManager() {} virtual void clear() = 0; QHostInfoCache cache; protected: - QAbstractHostInfoLookupManger() {} - static QAbstractHostInfoLookupManger* globalInstance(); + QAbstractHostInfoLookupManager() {} + static QAbstractHostInfoLookupManager* globalInstance(); }; #ifndef Q_OS_SYMBIAN -class QHostInfoLookupManager : public QAbstractHostInfoLookupManger +class QHostInfoLookupManager : public QAbstractHostInfoLookupManager { Q_OBJECT public: @@ -279,14 +279,14 @@ private: } iState; }; -class QSymbianHostInfoLookupManger : public QAbstractHostInfoLookupManger +class QSymbianHostInfoLookupManager : public QAbstractHostInfoLookupManager { Q_OBJECT public: - QSymbianHostInfoLookupManger(); - ~QSymbianHostInfoLookupManger(); + QSymbianHostInfoLookupManager(); + ~QSymbianHostInfoLookupManager(); - static QSymbianHostInfoLookupManger* globalInstance(); + static QSymbianHostInfoLookupManager* globalInstance(); int id(); void clear(); diff --git a/src/network/kernel/qhostinfo_symbian.cpp b/src/network/kernel/qhostinfo_symbian.cpp index a38a845..ded2416 100644 --- a/src/network/kernel/qhostinfo_symbian.cpp +++ b/src/network/kernel/qhostinfo_symbian.cpp @@ -221,7 +221,7 @@ QSymbianHostResolver::QSymbianHostResolver(const QString &hostName, int identifi QSymbianHostResolver::~QSymbianHostResolver() { #if defined(QHOSTINFO_DEBUG) - qDebug() << "QSymbianHostInfoLookupManger::~QSymbianHostResolver" << id(); + qDebug() << "QSymbianHostInfoLookupManager::~QSymbianHostResolver" << id(); #endif Cancel(); iHostResolver.Close(); @@ -236,7 +236,7 @@ void QSymbianHostResolver::requestHostLookup() iHostName.toLatin1().constData(), id()); #endif - QSymbianHostInfoLookupManger *manager = QSymbianHostInfoLookupManger::globalInstance(); + QSymbianHostInfoLookupManager *manager = QSymbianHostInfoLookupManager::globalInstance(); if (manager->cache.isEnabled()) { //check if name has been put in the cache while this request was queued bool valid; @@ -360,7 +360,7 @@ void QSymbianHostResolver::returnResults() #endif iState = EIdle; - QSymbianHostInfoLookupManger *manager = QSymbianHostInfoLookupManger::globalInstance(); + QSymbianHostInfoLookupManager *manager = QSymbianHostInfoLookupManager::globalInstance(); if (manager->cache.isEnabled()) { manager->cache.put(iHostName, iResults); } @@ -376,7 +376,7 @@ TInt QSymbianHostResolver::RunError(TInt aError) QT_TRY { iState = EIdle; - QSymbianHostInfoLookupManger *manager = QSymbianHostInfoLookupManger::globalInstance(); + QSymbianHostInfoLookupManager *manager = QSymbianHostInfoLookupManager::globalInstance(); manager->lookupFinished(this); setError_helper(iResults, aError); @@ -448,19 +448,19 @@ int QSymbianHostResolver::id() return iResults.lookupId(); } -QSymbianHostInfoLookupManger::QSymbianHostInfoLookupManger() +QSymbianHostInfoLookupManager::QSymbianHostInfoLookupManager() { } -QSymbianHostInfoLookupManger::~QSymbianHostInfoLookupManger() +QSymbianHostInfoLookupManager::~QSymbianHostInfoLookupManager() { } -void QSymbianHostInfoLookupManger::clear() +void QSymbianHostInfoLookupManager::clear() { QMutexLocker locker(&mutex); #if defined(QHOSTINFO_DEBUG) - qDebug() << "QSymbianHostInfoLookupManger::clear" << QThread::currentThreadId(); + qDebug() << "QSymbianHostInfoLookupManager::clear" << QThread::currentThreadId(); #endif //TODO: these aren't deleted because of thread unsafety, but that is a behaviour difference //qDeleteAll(iCurrentLookups); @@ -468,12 +468,12 @@ void QSymbianHostInfoLookupManger::clear() cache.clear(); } -void QSymbianHostInfoLookupManger::lookupFinished(QSymbianHostResolver *r) +void QSymbianHostInfoLookupManager::lookupFinished(QSymbianHostResolver *r) { QMutexLocker locker(&mutex); #if defined(QHOSTINFO_DEBUG) - qDebug() << "QSymbianHostInfoLookupManger::lookupFinished" << QThread::currentThreadId() << r->id() << "current" << iCurrentLookups.count() << "queued" << iScheduledLookups.count(); + qDebug() << "QSymbianHostInfoLookupManager::lookupFinished" << QThread::currentThreadId() << r->id() << "current" << iCurrentLookups.count() << "queued" << iScheduledLookups.count(); #endif // remove finished lookup from array and destroy TInt count = iCurrentLookups.count(); @@ -487,10 +487,10 @@ void QSymbianHostInfoLookupManger::lookupFinished(QSymbianHostResolver *r) runNextLookup(); } -void QSymbianHostInfoLookupManger::runNextLookup() +void QSymbianHostInfoLookupManager::runNextLookup() { #if defined(QHOSTINFO_DEBUG) - qDebug() << "QSymbianHostInfoLookupManger::runNextLookup" << QThread::currentThreadId() << "current" << iCurrentLookups.count() << "queued" << iScheduledLookups.count(); + qDebug() << "QSymbianHostInfoLookupManager::runNextLookup" << QThread::currentThreadId() << "current" << iCurrentLookups.count() << "queued" << iScheduledLookups.count(); #endif // check to see if there are any scheduled lookups if (iScheduledLookups.count() > 0) { @@ -503,12 +503,12 @@ void QSymbianHostInfoLookupManger::runNextLookup() } // called from QHostInfo -void QSymbianHostInfoLookupManger::scheduleLookup(QSymbianHostResolver* r) +void QSymbianHostInfoLookupManager::scheduleLookup(QSymbianHostResolver* r) { QMutexLocker locker(&mutex); #if defined(QHOSTINFO_DEBUG) - qDebug() << "QSymbianHostInfoLookupManger::scheduleLookup" << QThread::currentThreadId() << r->id() << "current" << iCurrentLookups.count() << "queued" << iScheduledLookups.count(); + qDebug() << "QSymbianHostInfoLookupManager::scheduleLookup" << QThread::currentThreadId() << r->id() << "current" << iCurrentLookups.count() << "queued" << iScheduledLookups.count(); #endif // Check to see if we have space on the current lookups pool. if (iCurrentLookups.count() >= KMaxConcurrentLookups) { @@ -527,12 +527,12 @@ void QSymbianHostInfoLookupManger::scheduleLookup(QSymbianHostResolver* r) } } -void QSymbianHostInfoLookupManger::abortLookup(int id) +void QSymbianHostInfoLookupManager::abortLookup(int id) { QMutexLocker locker(&mutex); #if defined(QHOSTINFO_DEBUG) - qDebug() << "QSymbianHostInfoLookupManger::abortLookup" << QThread::currentThreadId() << id << "current" << iCurrentLookups.count() << "queued" << iScheduledLookups.count(); + qDebug() << "QSymbianHostInfoLookupManager::abortLookup" << QThread::currentThreadId() << id << "current" << iCurrentLookups.count() << "queued" << iScheduledLookups.count(); #endif int i = 0; // Find the aborted lookup by ID. @@ -557,10 +557,10 @@ void QSymbianHostInfoLookupManger::abortLookup(int id) } } -QSymbianHostInfoLookupManger* QSymbianHostInfoLookupManger::globalInstance() +QSymbianHostInfoLookupManager* QSymbianHostInfoLookupManager::globalInstance() { - return static_cast - (QAbstractHostInfoLookupManger::globalInstance()); + return static_cast + (QAbstractHostInfoLookupManager::globalInstance()); } QT_END_NAMESPACE -- cgit v0.12 From a0ca845cd32178d789f4eeff602b283a290842b8 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Mon, 4 Apr 2011 18:26:00 +0100 Subject: Thread safety for QHostInfo symbian implementation Each thread needs at least one current request if it has any queued requests, this is to stop the queue stalling. When starting a queued request, start it in the same thread it belongs to When aborting a request from the wrong thread, just detach it (it will complete normally but the slot isn't connected, and then delete itself) Reviewed-by: Markus Goetz --- src/network/kernel/qhostinfo_p.h | 2 ++ src/network/kernel/qhostinfo_symbian.cpp | 54 ++++++++++++++++++++++++++------ 2 files changed, 46 insertions(+), 10 deletions(-) diff --git a/src/network/kernel/qhostinfo_p.h b/src/network/kernel/qhostinfo_p.h index bae6efa..8da0692 100644 --- a/src/network/kernel/qhostinfo_p.h +++ b/src/network/kernel/qhostinfo_p.h @@ -234,6 +234,7 @@ public: ~QSymbianHostResolver(); void requestHostLookup(); + void abortHostLookup(); int id(); void returnResults(); @@ -301,6 +302,7 @@ public: private: void runNextLookup(); + // this is true for single threaded use, with multiple threads the max is ((number of threads) + KMaxConcurrentLookups - 1) static const int KMaxConcurrentLookups = 5; QList iCurrentLookups; diff --git a/src/network/kernel/qhostinfo_symbian.cpp b/src/network/kernel/qhostinfo_symbian.cpp index ded2416..dcfc490 100644 --- a/src/network/kernel/qhostinfo_symbian.cpp +++ b/src/network/kernel/qhostinfo_symbian.cpp @@ -311,6 +311,23 @@ void QSymbianHostResolver::requestHostLookup() } } +void QSymbianHostResolver::abortHostLookup() +{ + if (resultEmitter.thread() == QThread::currentThread()) { +#ifdef QHOSTINFO_DEBUG + qDebug("QSymbianHostResolver::abortHostLookup - deleting %d", id()); +#endif + //normal case, abort from same thread it was started + delete this; //will cancel outstanding request + } else { +#ifdef QHOSTINFO_DEBUG + qDebug("QSymbianHostResolver::abortHostLookup - detaching %d", id()); +#endif + //abort from different thread, carry on but don't report the results + resultEmitter.disconnect(); + } +} + void QSymbianHostResolver::DoCancel() { #if defined(QHOSTINFO_DEBUG) @@ -462,9 +479,10 @@ void QSymbianHostInfoLookupManager::clear() #if defined(QHOSTINFO_DEBUG) qDebug() << "QSymbianHostInfoLookupManager::clear" << QThread::currentThreadId(); #endif - //TODO: these aren't deleted because of thread unsafety, but that is a behaviour difference - //qDeleteAll(iCurrentLookups); - //qDeleteAll(iScheduledLookups); + foreach (QSymbianHostResolver *hr, iCurrentLookups) + hr->abortHostLookup(); + iCurrentLookups.clear(); + qDeleteAll(iScheduledLookups); cache.clear(); } @@ -493,12 +511,17 @@ void QSymbianHostInfoLookupManager::runNextLookup() qDebug() << "QSymbianHostInfoLookupManager::runNextLookup" << QThread::currentThreadId() << "current" << iCurrentLookups.count() << "queued" << iScheduledLookups.count(); #endif // check to see if there are any scheduled lookups - if (iScheduledLookups.count() > 0) { - // if so, move one to the current lookups and run it - // FIFO - QSymbianHostResolver* hostResolver = iScheduledLookups.takeFirst(); - iCurrentLookups.append(hostResolver); - hostResolver->requestHostLookup(); + for (int i=0; iresultEmitter.thread() == QThread::currentThread()) { + // if so, move one to the current lookups and run it + iCurrentLookups.append(hostResolver); + iScheduledLookups.removeAt(i); + hostResolver->requestHostLookup(); + // if spare capacity, try to start another one + if (iCurrentLookups.count() >= KMaxConcurrentLookups) + break; + } } } @@ -511,7 +534,18 @@ void QSymbianHostInfoLookupManager::scheduleLookup(QSymbianHostResolver* r) qDebug() << "QSymbianHostInfoLookupManager::scheduleLookup" << QThread::currentThreadId() << r->id() << "current" << iCurrentLookups.count() << "queued" << iScheduledLookups.count(); #endif // Check to see if we have space on the current lookups pool. + bool defer = false; if (iCurrentLookups.count() >= KMaxConcurrentLookups) { + // busy, defer unless there are no request in this thread + // at least one active request per thread with queued requests is needed + for (int i=0; i < iCurrentLookups.count();i++) { + if (iCurrentLookups.at(i)->resultEmitter.thread() == QThread::currentThread()) { + defer = true; + break; + } + } + } + if (defer) { // If no, schedule for later. iScheduledLookups.append(r); #if defined(QHOSTINFO_DEBUG) @@ -541,7 +575,7 @@ void QSymbianHostInfoLookupManager::abortLookup(int id) if (id == iCurrentLookups[i]->id()) { QSymbianHostResolver* r = iCurrentLookups.at(i); iCurrentLookups.removeAt(i); - delete r; //cancels via destructor + r->abortHostLookup(); runNextLookup(); return; } -- cgit v0.12 From 4aef1e1dd1ec5ccfdf56d91975185ff96a51701b Mon Sep 17 00:00:00 2001 From: Aaron Tunney Date: Tue, 5 Apr 2011 11:45:24 +0100 Subject: Updating comment in QHostInfo::localDomainName Updating comment to indicate that the feature isn't supported on Symbian. Reviewed-by: Shane Kearns --- src/network/kernel/qhostinfo_symbian.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/network/kernel/qhostinfo_symbian.cpp b/src/network/kernel/qhostinfo_symbian.cpp index dcfc490..40ede54 100644 --- a/src/network/kernel/qhostinfo_symbian.cpp +++ b/src/network/kernel/qhostinfo_symbian.cpp @@ -206,7 +206,9 @@ QString QHostInfo::localHostName() QString QHostInfo::localDomainName() { - // TODO - fill with code. + // This concept does not exist on Symbian OS because the device can be on + // multiple networks with multiple "local domain" names. + // For now, return a null string. return QString(); } -- cgit v0.12 From dc474b5d19f66dc3ede087ae6fa8ec6f9245477e Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 5 Apr 2011 15:17:52 +0100 Subject: Add autotests for QHostInfo::abortHostLookup Test calling the abort from the same thread or from a different thread. The different thread is to check thread safety of the API. Reviewed-by: Markus Goetz --- tests/auto/qhostinfo/tst_qhostinfo.cpp | 49 ++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/tests/auto/qhostinfo/tst_qhostinfo.cpp b/tests/auto/qhostinfo/tst_qhostinfo.cpp index 7b2fc55..0e9319f 100644 --- a/tests/auto/qhostinfo/tst_qhostinfo.cpp +++ b/tests/auto/qhostinfo/tst_qhostinfo.cpp @@ -134,6 +134,8 @@ private slots: void cache(); + void abortHostLookup(); + void abortHostLookupInDifferentThread(); protected slots: void resultsReady(const QHostInfo &); @@ -583,5 +585,52 @@ void tst_QHostInfo::resultsReady(const QHostInfo &hi) QMetaObject::invokeMethod(&QTestEventLoop::instance(), "exitLoop", Qt::QueuedConnection); } +void tst_QHostInfo::abortHostLookup() +{ + //reset counter + lookupsDoneCounter = 0; + bool valid = false; + int id = -1; + QHostInfo result = qt_qhostinfo_lookup("qt.nokia.com", this, SLOT(resultsReady(QHostInfo)), &valid, &id); + QVERIFY(!valid); + //it is assumed that the DNS request/response in the backend is slower than it takes to call abort + QHostInfo::abortHostLookup(id); + QTestEventLoop::instance().enterLoop(5); + QCOMPARE(lookupsDoneCounter, 0); +} + +class LookupAborter : public QObject +{ + Q_OBJECT +public slots: + void abort() + { + QHostInfo::abortHostLookup(id); + QThread::currentThread()->quit(); + } +public: + int id; +}; + +void tst_QHostInfo::abortHostLookupInDifferentThread() +{ + //reset counter + lookupsDoneCounter = 0; + bool valid = false; + int id = -1; + QHostInfo result = qt_qhostinfo_lookup("qt.nokia.com", this, SLOT(resultsReady(QHostInfo)), &valid, &id); + QVERIFY(!valid); + QThread thread; + LookupAborter aborter; + aborter.id = id; + aborter.moveToThread(&thread); + connect(&thread, SIGNAL(started()), &aborter, SLOT(abort())); + //it is assumed that the DNS request/response in the backend is slower than it takes to schedule the thread and call abort + thread.start(); + QVERIFY(thread.wait(5000)); + QTestEventLoop::instance().enterLoop(5); + QCOMPARE(lookupsDoneCounter, 0); +} + QTEST_MAIN(tst_QHostInfo) #include "tst_qhostinfo.moc" -- cgit v0.12 From 3915dd40b967fbf96a53820a8130342280a5b299 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 5 Apr 2011 16:30:19 +0100 Subject: QHostInfo symbian backend finalisation For reverse lookups, don't report errors, instead just return the IP address as a string for the host name (for behavioural compability with the windows and unix backends) Don't sort IP4 addresses before IP6 addresses for the same host. The symbian host resolver internally sorts the list so the usable addresses are returned first. (usable means has a valid route) Task-number: QTBUG-18135 Reviewed-by: Markus Goetz --- src/network/kernel/qhostinfo_symbian.cpp | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/network/kernel/qhostinfo_symbian.cpp b/src/network/kernel/qhostinfo_symbian.cpp index 40ede54..2a8de1d 100644 --- a/src/network/kernel/qhostinfo_symbian.cpp +++ b/src/network/kernel/qhostinfo_symbian.cpp @@ -117,11 +117,13 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName, QSharedPointer() << address); } + results.setAddresses(QList() << address); return results; } @@ -188,8 +190,7 @@ QString QHostInfo::localHostName() RSocketServ socketServ(qt_symbianGetSocketServer()); RHostResolver hostResolver; - // Will return both IPv4 and IPv6 - // TODO: Pass RHostResolver.Open() the global RConnection + // RConnection not required to get the host name int err = hostResolver.Open(socketServ, KAfInet, KProtocolInetUdp); if (err) return QString(); @@ -420,13 +421,7 @@ void QSymbianHostResolver::processNameResult() // Ensure that record is valid (not an alias and with length greater than 0) if (!(iNameResult().iFlags & TNameRecord::EAlias) && !(hostAdd.IsUnspecified())) { - if (iNameResult().iAddr.Family() == KAfInet) { - // IPv4 - prepend - iHostAddresses.prepend(QHostAddress(qt_TDesC2QString(ipAddr))); - } else { - // IPv6 - append - iHostAddresses.append(QHostAddress(qt_TDesC2QString(ipAddr))); - } + iHostAddresses.append(QHostAddress(qt_TDesC2QString(ipAddr))); } iState = EGetByName; @@ -453,11 +448,13 @@ void QSymbianHostResolver::processAddressResult() TInt err = iStatus.Int(); if (err < 0) { - setError_helper(iResults, err); + //For behavioural compatibility with Qt 4.7, don't report errors on reverse lookup, + //return the address as a string (same as unix/windows backends) + iResults.setHostName(iAddress.toString()); } else { iResults.setHostName(qt_TDesC2QString(iNameResult().iName)); - iResults.setAddresses(QList() << iAddress); } + iResults.setAddresses(QList() << iAddress); returnResults(); } @@ -523,6 +520,7 @@ void QSymbianHostInfoLookupManager::runNextLookup() // if spare capacity, try to start another one if (iCurrentLookups.count() >= KMaxConcurrentLookups) break; + i--; //compensate for removeAt } } } -- cgit v0.12 From 76ef8d709b7bb0458153df85f60b39937664811b Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 5 Apr 2011 16:37:08 +0100 Subject: QHostInfo autotest fixes related to symbian 1. start default network at start of test (this makes the test faster and more reliable, as the network can be stopped automatically if we don't use a network session) 2. remove unnecessary ifdef from the ipv4 data 3. add new IPv6 test hosts to the ipv6 data 4. extend ipv6 timeout to match the ipv4 timeout 5. check error in LookupThread::run() to avoid test crashing on failure 6. extend timeout for multipleDifferentLookups (uncached DNS is SLOW) 7. enable IPv6 lookups on symbian statically (don't use the broken POSIX functions) Reviewed-by: Markus Goetz --- tests/auto/qhostinfo/tst_qhostinfo.cpp | 49 +++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/tests/auto/qhostinfo/tst_qhostinfo.cpp b/tests/auto/qhostinfo/tst_qhostinfo.cpp index 0e9319f..af0631e 100644 --- a/tests/auto/qhostinfo/tst_qhostinfo.cpp +++ b/tests/auto/qhostinfo/tst_qhostinfo.cpp @@ -62,6 +62,12 @@ #include #include +#ifndef QT_NO_BEARERMANAGEMENT +#include +#include +#include +#endif + #include #include #if defined(Q_OS_WIN32) || defined(Q_OS_WINCE) @@ -145,6 +151,11 @@ private: bool lookupDone; int lookupsDoneCounter; QHostInfo lookupResults; +#ifndef QT_NO_BEARERMANAGEMENT + QNetworkConfigurationManager *netConfMan; + QNetworkConfiguration networkConfiguration; + QScopedPointer networkSession; +#endif }; // Testing get/set functions @@ -185,6 +196,21 @@ tst_QHostInfo::~tst_QHostInfo() void tst_QHostInfo::initTestCase() { +#ifndef QT_NO_BEARERMANAGEMENT + //start the default network + netConfMan = new QNetworkConfigurationManager(this); + networkConfiguration = netConfMan->defaultConfiguration(); + networkSession.reset(new QNetworkSession(networkConfiguration)); + if (!networkSession->isOpen()) { + networkSession->open(); + QVERIFY(networkSession->waitForOpened(30000)); + } +#endif + +#ifdef Q_OS_SYMBIAN + ipv6Available = true; + ipv6LookupsAvailable = true; +#else ipv6Available = false; ipv6LookupsAvailable = false; #if !defined(QT_NO_GETADDRINFO) @@ -207,6 +233,7 @@ void tst_QHostInfo::initTestCase() } } #endif +#endif QTcpServer server; if (server.listen(QHostAddress("::1"))) { @@ -240,18 +267,14 @@ void tst_QHostInfo::lookupIPv4_data() QTest::addColumn("addresses"); QTest::addColumn("err"); -#ifdef Q_OS_SYMBIAN // Test server lookup QTest::newRow("lookup_01") << QtNetworkSettings::serverName() << QtNetworkSettings::serverIP().toString() << int(QHostInfo::NoError); - QTest::newRow("literal_ip4") << QtNetworkSettings::serverIP().toString() << QtNetworkSettings::serverIP().toString() << int(QHostInfo::NoError); - QTest::newRow("multiple_ip4") << "multi.dev.troll.no" << "1.2.3.4 1.2.3.5 10.3.3.31" << int(QHostInfo::NoError); -#else QTest::newRow("empty") << "" << "" << int(QHostInfo::HostNotFound); QTest::newRow("single_ip4") << "lupinella.troll.no" << lupinellaIp << int(QHostInfo::NoError); QTest::newRow("multiple_ip4") << "multi.dev.troll.no" << "1.2.3.4 1.2.3.5 10.3.3.31" << int(QHostInfo::NoError); QTest::newRow("literal_ip4") << lupinellaIp << lupinellaIp << int(QHostInfo::NoError); -#endif + QTest::newRow("notfound") << "this-name-does-not-exist-hopefully." << "" << int(QHostInfo::HostNotFound); QTest::newRow("idn-ace") << "xn--alqualond-34a.troll.no" << "10.3.3.55" << int(QHostInfo::NoError); @@ -293,8 +316,11 @@ void tst_QHostInfo::lookupIPv6_data() QTest::addColumn("addresses"); QTest::addColumn("err"); - QTest::newRow("ip6") << "www.ipv6-net.org" << "62.93.217.177 2001:618:1401:0:0:0:0:4" << int(QHostInfo::NoError); - QTest::newRow("ip6") << "ipv6.google.com" << "2A00:1450:8007:0:0:0:0:63" << int(QHostInfo::NoError); + QTest::newRow("ipv6-net") << "www.ipv6-net.org" << "62.93.217.177 2001:618:1401:0:0:0:0:4" << int(QHostInfo::NoError); + QTest::newRow("ipv6-test") << "ipv6-test.dev.troll.no" << "2001:638:a00:2:0:0:0:2" << int(QHostInfo::NoError); + QTest::newRow("dns6-test") << "dns6-test-dev.troll.no" << "2001:470:1f01:115:0:0:0:10" << int(QHostInfo::NoError); + QTest::newRow("multi-dns6") << "multi-dns6-test-dev.troll.no" << "2001:470:1f01:115:0:0:0:11 2001:470:1f01:115:0:0:0:12" << int(QHostInfo::NoError); + QTest::newRow("dns46-test") << "dns46-test-dev.troll.no" << "10.3.4.90 2001:470:1f01:115:0:0:0:13" << int(QHostInfo::NoError); // avoid using real IPv6 addresses here because this will do a DNS query // real addresses are between 2000:: and 3fff:ffff:ffff:ffff:ffff:ffff:ffff @@ -314,7 +340,7 @@ void tst_QHostInfo::lookupIPv6() lookupDone = false; QHostInfo::lookupHost(hostname, this, SLOT(resultsReady(const QHostInfo&))); - QTestEventLoop::instance().enterLoop(3); + QTestEventLoop::instance().enterLoop(10); QVERIFY(!QTestEventLoop::instance().timeout()); QVERIFY(lookupDone); @@ -415,6 +441,8 @@ protected: inline void run() { QHostInfo info = QHostInfo::fromName("qt.nokia.com"); + QCOMPARE(info.error(), QHostInfo::NoError); + QVERIFY(info.addresses().count() > 0); QCOMPARE(info.addresses().at(0).toString(), QString("87.238.50.178")); } }; @@ -532,8 +560,9 @@ void tst_QHostInfo::multipleDifferentLookups() QElapsedTimer timer; timer.start(); - while (timer.elapsed() < 10000 && lookupsDoneCounter < repeats*COUNT) { + while (timer.elapsed() < 60000 && lookupsDoneCounter < repeats*COUNT) { QTestEventLoop::instance().enterLoop(2); + //qDebug() << "t:" << timer.elapsed(); } QCOMPARE(lookupsDoneCounter, repeats*COUNT); } @@ -574,7 +603,7 @@ void tst_QHostInfo::cache() QVERIFY(result.addresses().isEmpty()); // the slot should have been called 2 times. - QVERIFY(lookupsDoneCounter == 2); + QCOMPARE(lookupsDoneCounter, 2); } void tst_QHostInfo::resultsReady(const QHostInfo &hi) -- cgit v0.12 From 397e139774eaaee88dc44cd47d296646ec03aed7 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Wed, 6 Apr 2011 12:16:36 +0200 Subject: tst_qtcpserver: Add a mapped v4 addr test Reviewed-by: Shane Kearns --- tests/auto/qtcpserver/tst_qtcpserver.cpp | 35 ++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/auto/qtcpserver/tst_qtcpserver.cpp b/tests/auto/qtcpserver/tst_qtcpserver.cpp index cff2fe5..9cddc00 100644 --- a/tests/auto/qtcpserver/tst_qtcpserver.cpp +++ b/tests/auto/qtcpserver/tst_qtcpserver.cpp @@ -97,6 +97,7 @@ private slots: void constructing(); void clientServerLoop(); void ipv6Server(); + void ipv6ServerMapped(); void crashTests(); void maxPendingConnections(); void listenError(); @@ -265,6 +266,40 @@ void tst_QTcpServer::ipv6Server() } //---------------------------------------------------------------------------------- +void tst_QTcpServer::ipv6ServerMapped() +{ + QFETCH_GLOBAL(bool, setProxy); + if (setProxy) + return; + + QTcpServer server; + QVERIFY(server.listen(QHostAddress::LocalHost)); + + // let's try the normal case + QTcpSocket client1; + client1.connectToHost("127.0.0.1", server.serverPort()); + QVERIFY(server.waitForNewConnection(5000)); + delete server.nextPendingConnection(); + + // let's try the mapped one in the nice format + QTcpSocket client2; + client2.connectToHost("::ffff:127.0.0.1", server.serverPort()); + QVERIFY(server.waitForNewConnection(5000)); + delete server.nextPendingConnection(); + + // let's try the mapped in hex format + QTcpSocket client3; + client3.connectToHost("::ffff:7F00:0001", server.serverPort()); + QVERIFY(server.waitForNewConnection(5000)); + delete server.nextPendingConnection(); + + // However connecting to the v6 localhost should not work + QTcpSocket client4; + client4.connectToHost("::1", server.serverPort()); + QVERIFY(!server.waitForNewConnection(5000)); +} + +//---------------------------------------------------------------------------------- void tst_QTcpServer::crashTests() { QTcpServer server; -- cgit v0.12 From 31c588cfe42c387aef8c541fe1e6d50e9ff51560 Mon Sep 17 00:00:00 2001 From: Martin Petersson Date: Wed, 6 Apr 2011 12:32:36 +0200 Subject: tst_qnetworkreply: skip ioGetFromBuiltinHttp test. Reviewed-by: Markus Goetz --- tests/auto/qnetworkreply/tst_qnetworkreply.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp index 11f4fc3..10fce94 100644 --- a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp @@ -4265,6 +4265,7 @@ void tst_QNetworkReply::ioGetFromBuiltinHttp_data() void tst_QNetworkReply::ioGetFromBuiltinHttp() { + QSKIP("Limiting is broken right now, check QTBUG-15065", SkipAll); QFETCH(bool, https); QFETCH(int, bufferSize); -- cgit v0.12 From a12d41076919a133e63de63dff5c1a131a0564e4 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 7 Apr 2011 10:37:31 +0300 Subject: Have the backing store destroyed also in special Symbian scenarios. The backing store tracker's registerWidget and unregisterWidget functions are called when EPartiallyVisible and ENotVisible events come from WSERV. However if an application sends its window group to background right after caling show() and before entering the event loop, there is a chance that all the application will receive is an ENotVisible event, leading to calling unregisterWidget() without a previous registerWidget(). In this case the backing store was not destroyed and the application was consuming GPU memory even while it was staying in background. This patch makes unregisterWidget() not to check the widget's presence in the m_widgets set, instead the condition for deleting the backing store is solely an empty set. Task-number: QTBUG-18493 Reviewed-by: Gareth Stockwell --- src/gui/kernel/qwidget.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index 0a73481..be615a4 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -234,7 +234,8 @@ void QWidgetBackingStoreTracker::registerWidget(QWidget *w) */ void QWidgetBackingStoreTracker::unregisterWidget(QWidget *w) { - if (m_widgets.remove(w) && m_widgets.isEmpty()) { + m_widgets.remove(w); + if (m_widgets.isEmpty()) { delete m_ptr; m_ptr = 0; } -- cgit v0.12 From c2383fa6a8070bf5bec4a444ae7d486874f35ab2 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Wed, 6 Apr 2011 17:20:33 +0300 Subject: Do not unnecessarily draw application twice in landscape Fullscreen with softkeys dialogs would draw twice when orientation was changed to landscape, causing flicker. This happened because status pane change event and layout change event both caused redraw with different client area size. Added a check to avoid handling client area change on account of status pane change, if status pane is not visible and there was no change in its visibility. Task-number: QTBUG-18496 Reviewed-by: Sami Merila --- src/gui/kernel/qapplication_s60.cpp | 9 ++++++++- src/gui/kernel/qt_s60_p.h | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index 21b50b6..a8680b9 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -459,6 +459,7 @@ QSymbianControl::QSymbianControl(QWidget *w) , m_ignoreFocusChanged(0) , m_symbianPopupIsOpen(0) , m_inExternalScreenOverride(false) + , m_lastStatusPaneVisibility(0) { } @@ -1427,7 +1428,13 @@ void QSymbianControl::HandleResourceChange(int resourceType) } break; case KInternalStatusPaneChange: - handleClientAreaChange(); + // When status pane is not visible, only handle client area change if status pane was + // previously visible, as size changes to hidden status pane should not affect + // client area. + if (S60->statusPane() && (S60->statusPane()->IsVisible() || m_lastStatusPaneVisibility)) { + m_lastStatusPaneVisibility = S60->statusPane()->IsVisible(); + handleClientAreaChange(); + } if (IsFocused() && IsVisible()) { qwidget->d_func()->setWindowIcon_sys(true); qwidget->d_func()->setWindowTitle_sys(qwidget->windowTitle()); diff --git a/src/gui/kernel/qt_s60_p.h b/src/gui/kernel/qt_s60_p.h index ee0b862..c48bf63 100644 --- a/src/gui/kernel/qt_s60_p.h +++ b/src/gui/kernel/qt_s60_p.h @@ -295,6 +295,7 @@ private: #endif bool m_inExternalScreenOverride : 1; + bool m_lastStatusPaneVisibility : 1; }; inline QS60Data::QS60Data() -- cgit v0.12 From 99eb6c6c2048ce4d96348c54a79986c779fdf656 Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Thu, 7 Apr 2011 13:52:42 +0200 Subject: Support QMAKE_LFLAGS.ARMCC and QMAKE_LFLAGS.GCCE in makefile build system Reviewed-by: axis --- mkspecs/common/symbian/symbian.conf | 3 ++- mkspecs/features/symbian/symbian_building.prf | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/mkspecs/common/symbian/symbian.conf b/mkspecs/common/symbian/symbian.conf index e35786b..f955e3c 100644 --- a/mkspecs/common/symbian/symbian.conf +++ b/mkspecs/common/symbian/symbian.conf @@ -57,7 +57,8 @@ QMAKE_INCDIR = QMAKE_INCDIR_QT = $$[QT_INSTALL_HEADERS] QMAKE_LFLAGS = -QMAKE_LFLAGS.ARMCC = +QMAKE_LFLAGS.ARMCC = +QMAKE_LFLAGS.GCCE = QMAKE_LFLAGS_EXCEPTIONS_ON = QMAKE_LFLAGS_EXCEPTIONS_OFF = QMAKE_LFLAGS_RELEASE = diff --git a/mkspecs/features/symbian/symbian_building.prf b/mkspecs/features/symbian/symbian_building.prf index 28046b4..8c75707 100644 --- a/mkspecs/features/symbian/symbian_building.prf +++ b/mkspecs/features/symbian/symbian_building.prf @@ -1,6 +1,7 @@ symbian-armcc { QMAKE_CFLAGS += $$QMAKE_CFLAGS.ARMCC QMAKE_CXXFLAGS += $$QMAKE_CXXFLAGS.ARMCC + QMAKE_LFLAGS += $$QMAKE_LFLAGS.ARMCC # This is to prevent inclusion of the shipped RVCT headers, which are often in the # environment variable RVCTxxINC by default. -J prevents the searching of that location, # but needs a path, so just specify somewhere guaranteed not to contain header files. @@ -9,6 +10,7 @@ symbian-armcc { } else:symbian-gcce { QMAKE_CFLAGS += $$QMAKE_CFLAGS.GCCE QMAKE_CXXFLAGS += $$QMAKE_CXXFLAGS.GCCE + QMAKE_LFLAGS += $$QMAKE_LFLAGS.GCCE } # We need a target name without the INFIX'ed part, since flags are not infixed. -- cgit v0.12 From 2eae397d7c4e549f7c77f0bc7e22f0d9390c7ec3 Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Thu, 7 Apr 2011 13:53:44 +0200 Subject: Correct some parameters for the makefile build sytem, armcc and gcce Reviewed-by: axis --- mkspecs/symbian-armcc/qmake.conf | 6 +++--- mkspecs/symbian-gcce/qmake.conf | 7 +++---- src/gui/gui.pro | 8 +++----- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/mkspecs/symbian-armcc/qmake.conf b/mkspecs/symbian-armcc/qmake.conf index 77a1966..2de3218 100644 --- a/mkspecs/symbian-armcc/qmake.conf +++ b/mkspecs/symbian-armcc/qmake.conf @@ -12,7 +12,7 @@ QMAKE_RVCT_LINKSTYLE = 1 #QMAKE_qtmain_CXXFLAGS = --arm #QMAKE_QtCore_CXXFLAGS = -QMAKE_QtGui_LFLAGS = "--rw-base 0x800000" +#QMAKE_QtGui_LFLAGS = "--rw-base 0x800000" #QMAKE_QtDBus_CXXFLAGS = #QMAKE_QtDeclarative_CXXFLAGS = #QMAKE_QtMultimedia_CXXFLAGS = @@ -27,9 +27,9 @@ QMAKE_QtGui_LFLAGS = "--rw-base 0x800000" #QMAKE_QtTest_CXXFLAGS = #QMAKE_QtXmlPatterns_CXXFLAGS = #QMAKE_QtXml_CXXFLAGS = -QMAKE_QtWebKit_CXXFLAGS = --arm +#QMAKE_QtWebKit_CXXFLAGS = --arm # Move RW-section base address to start from 0xE00000 instead of the toolchain default 0x400000. -QMAKE_QtWebKit_LFLAGS = --rw-base 0xE00000 +#QMAKE_QtWebKit_LFLAGS = --rw-base 0xE00000 QMAKE_CFLAGS += --dllimport_runtime --diag_suppress 186,611,654,1300 --thumb --fpu softvfp --cpu 5T --enum_is_int -Ono_known_library --fpmode ieee_no_fenv --no_vfe --apcs /inter QMAKE_CXXFLAGS += $$QMAKE_CFLAGS diff --git a/mkspecs/symbian-gcce/qmake.conf b/mkspecs/symbian-gcce/qmake.conf index 62a079b..38042e9 100644 --- a/mkspecs/symbian-gcce/qmake.conf +++ b/mkspecs/symbian-gcce/qmake.conf @@ -19,7 +19,7 @@ QMAKE_AR = arm-none-symbianelf-ar cqs QMAKE_qtmain_CXXFLAGS = -mthumb QMAKE_QtCore_CXXFLAGS = -mthumb -QMAKE_QtGui_LFLAGS = -Ttext 0x8000 -Tdata 0xE00000 +#QMAKE_QtGui_LFLAGS = -Ttext 0x8000 -Tdata 0xE00000 QMAKE_QtDBus_CXXFLAGS = -mthumb QMAKE_QtDeclarative_CXXFLAGS = -mthumb QMAKE_QtMultimedia_CXXFLAGS = -mthumb @@ -34,8 +34,7 @@ QMAKE_QtSvg_CXXFLAGS = -mthumb QMAKE_QtTest_CXXFLAGS = -mthumb QMAKE_QtXmlPatterns_CXXFLAGS = -mthumb QMAKE_QtXml_CXXFLAGS = -mthumb -#TODO fails with; arm-none-symbianelf-ld: section .data loaded at [00e00000,00e05973] overlaps section .text loaded at [00008000,00fe748b] -QMAKE_QtWebKit_LFLAGS = -Ttext 0x8000 -Tdata 0xE00000 +#QMAKE_QtWebKit_LFLAGS = -Ttext 0x8000 -Tdata 0xE00000 # never use -fPIC, gcce-linker doesn't like it. # g++ conf above adds it if the host platform is 64 bit, so we remove it again @@ -58,7 +57,7 @@ QMAKE_LFLAGS_PLUGIN += $$QMAKE_LFLAGS_SHLIB gcceExtraFlags = --include=$${EPOCROOT}epoc32/include/gcce/gcce.h -march=armv5t -mapcs -mthumb-interwork -nostdinc -c -msoft-float -T script QMAKE_CFLAGS += $${gcceExtraFlags} -QMAKE_CXXFLAGS += $${gcceExtraFlags} -x c++ -fexceptions -fno-unit-at-a-time -fvisibility-inlines-hidden +QMAKE_CXXFLAGS += $${gcceExtraFlags} -x c++ -fexceptions -fno-unit-at-a-time -fvisibility-inlines-hidden -Os #If we are not going to link to Qt or qtmain.lib, we need to include this at least once. isEmpty(QT):contains(TEMPLATE, app) { QMAKE_CXXFLAGS += --include=$${EPOCROOT}epoc32/include/stdapis/staticlibinit_gcce.h diff --git a/src/gui/gui.pro b/src/gui/gui.pro index 4d51fa8..cf492d6 100644 --- a/src/gui/gui.pro +++ b/src/gui/gui.pro @@ -55,11 +55,9 @@ DEFINES += Q_INTERNAL_QAPP_SRC symbian { TARGET.UID3=0x2001B2DD - symbian-abld|symbian-sbsv2 { - # ro-section in gui can exceed default allocated space, so move rw-section a little further - QMAKE_LFLAGS.ARMCC += --rw-base 0x800000 - QMAKE_LFLAGS.GCCE += -Tdata 0xC00000 - } + # ro-section in gui can exceed default allocated space, so move rw-section a little further + QMAKE_LFLAGS.ARMCC += --rw-base 0x800000 + QMAKE_LFLAGS.GCCE += -Tdata 0x800000 } neon:*-g++* { -- cgit v0.12 From 3a8006907634e5d4c02822d5ce14d558dee8b930 Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Thu, 7 Apr 2011 13:54:26 +0200 Subject: Add the rules for gcce in do_not_build_as_thumb.prf Reviewed-by: axis --- mkspecs/features/symbian/do_not_build_as_thumb.prf | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mkspecs/features/symbian/do_not_build_as_thumb.prf b/mkspecs/features/symbian/do_not_build_as_thumb.prf index 0f1fd9f..91a63c2 100644 --- a/mkspecs/features/symbian/do_not_build_as_thumb.prf +++ b/mkspecs/features/symbian/do_not_build_as_thumb.prf @@ -5,4 +5,9 @@ symbian-abld|symbian-sbsv2 { QMAKE_CFLAGS += --arm QMAKE_CXXFLAGS -= --thumb QMAKE_CXXFLAGS += --arm +} else:symbian-gcce { + QMAKE_CFLAGS -= --thumb + QMAKE_CFLAGS += -marm -mthumb-interwork -mapcs + QMAKE_CXXFLAGS -= --thumb + QMAKE_CXXFLAGS += -marm -mthumb-interwork -mapcs } -- cgit v0.12 From a29a5862b32e36735f7014c8fc9083823bd3fbaa Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Thu, 7 Apr 2011 13:58:46 +0200 Subject: Enable webkit build for the makefile build system with gcce Task-number: QTBUG-18484 Task-number: WEBKIT-57841 Reviewed-by: axis Reviewed-by: Janne Koskinen --- src/3rdparty/webkit/JavaScriptCore/wtf/MathExtras.h | 2 +- src/3rdparty/webkit/WebCore/WebCore.pro | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/3rdparty/webkit/JavaScriptCore/wtf/MathExtras.h b/src/3rdparty/webkit/JavaScriptCore/wtf/MathExtras.h index f8bace4..9349b48 100644 --- a/src/3rdparty/webkit/JavaScriptCore/wtf/MathExtras.h +++ b/src/3rdparty/webkit/JavaScriptCore/wtf/MathExtras.h @@ -190,7 +190,7 @@ inline float deg2turn(float d) { return d / 360.0f; } inline float rad2grad(float r) { return r * 200.0f / piFloat; } inline float grad2rad(float g) { return g * piFloat / 200.0f; } -#if !COMPILER(MSVC) && !COMPILER(RVCT) && !OS(ANDROID) && !COMPILER(WINSCW) +#if !COMPILER(MSVC) && !OS(ANDROID) && !OS(SYMBIAN) using std::isfinite; using std::isinf; using std::isnan; diff --git a/src/3rdparty/webkit/WebCore/WebCore.pro b/src/3rdparty/webkit/WebCore/WebCore.pro index 37d216d..c70a168 100644 --- a/src/3rdparty/webkit/WebCore/WebCore.pro +++ b/src/3rdparty/webkit/WebCore/WebCore.pro @@ -37,15 +37,14 @@ symbian: { # Need to guarantee that these come before system includes of /epoc32/include MMP_RULES += "USERINCLUDE rendering" MMP_RULES += "USERINCLUDE platform/text" - symbian-abld|symbian-sbsv2 { - # RO text (code) section in qtwebkit.dll exceeds allocated space for gcce udeb target. - # Move RW-section base address to start from 0xE00000 instead of the toolchain default 0x400000. - QMAKE_LFLAGS.ARMCC += --rw-base 0xE00000 - MMP_RULES += ALWAYS_BUILD_AS_ARM - } else { - QMAKE_CFLAGS -= --thumb - QMAKE_CXXFLAGS -= --thumb - } + + # RO text (code) section in qtwebkit.dll exceeds allocated space for gcce udeb target. + # Move RW-section base address to start from 0xE00000 instead of the toolchain default 0x400000. + QMAKE_LFLAGS.ARMCC += --rw-base 0xE00000 + QMAKE_LFLAGS.GCCE += -Tdata 0x1000000 + + CONFIG += do_not_build_as_thumb + CONFIG(release, debug|release): QMAKE_CXXFLAGS.ARMCC += -OTime -O3 } -- cgit v0.12 From 8e14e026cfba15cb6e07044922532fbb0bed767c Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Thu, 7 Apr 2011 14:00:48 +0200 Subject: Enable webkit for symbian-gcce in configure Reviewed-by: axis --- configure | 1 - 1 file changed, 1 deletion(-) diff --git a/configure b/configure index 62eb009..4c8ac11 100755 --- a/configure +++ b/configure @@ -7120,7 +7120,6 @@ EOF canBuildQtConcurrent="no" ;; symbian-gcce) - canBuildWebKit="no" canBuildQtConcurrent="no" ;; symbian-armcc) -- cgit v0.12 From e81ef9c4744a759783af03ddb01508386b5f33cd Mon Sep 17 00:00:00 2001 From: Sami Merila Date: Thu, 7 Apr 2011 15:43:06 +0300 Subject: Labels are not visible in dialogs with all themes QS60Style uses different theme background for dialogs. However, labels use just one color irregardless of background texture. Therefore, in certain themes, this might produce an issue, where foreground color (label) is not visible from background. To fix this, set the label color to correct theme color when label is contained within a dialog. Task-number: QT-4559 Reviewed-by: Tomi Vihria --- src/gui/styles/qs60style.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/gui/styles/qs60style.cpp b/src/gui/styles/qs60style.cpp index 05243a7..879d2e8 100644 --- a/src/gui/styles/qs60style.cpp +++ b/src/gui/styles/qs60style.cpp @@ -683,6 +683,13 @@ void QS60StylePrivate::setThemePalette(QWidget *widget) if (header->viewport()) header->viewport()->setPalette(widgetPalette); QApplication::setPalette(widgetPalette, "QHeaderView"); + } else if (qobject_cast(widget)) { + if (widget->window() && widget->window()->windowType() == Qt::Dialog) { + QPalette widgetPalette = widget->palette(); + widgetPalette.setColor(QPalette::WindowText, + s60Color(QS60StyleEnums::CL_QsnTextColors, 19, 0)); + widget->setPalette(widgetPalette); + } } } -- cgit v0.12 From 63064c275481d0e694838e90dead784b53dc10aa Mon Sep 17 00:00:00 2001 From: Sami Merila Date: Thu, 7 Apr 2011 15:50:07 +0300 Subject: Labels are not visible in dialogs with all themes (part2) Added include to the previous fix to prevent compilation issue. Task-number: QT-4559 Reviewed-by: Tomi Vihria --- src/gui/styles/qs60style.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/styles/qs60style.cpp b/src/gui/styles/qs60style.cpp index 879d2e8..4b76985 100644 --- a/src/gui/styles/qs60style.cpp +++ b/src/gui/styles/qs60style.cpp @@ -72,6 +72,7 @@ #include "qcheckbox.h" #include "qdesktopwidget.h" #include "qprogressbar.h" +#include "qlabel.h" #include "private/qtoolbarextension_p.h" #include "private/qcombobox_p.h" -- cgit v0.12 From a41345b6a6f2ed6e8c1a3442aba8259bb87f9fed Mon Sep 17 00:00:00 2001 From: Ruth Sadler Date: Thu, 7 Apr 2011 14:34:18 +0100 Subject: Check the validity of qt_desktopWidget before dereferencing Task-number: QTMOBILITY-1494 Reviewed-by: Gareth Stockwell --- src/gui/kernel/qapplication_s60.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index a8680b9..f80b657 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -1448,8 +1448,10 @@ void QSymbianControl::HandleResourceChange(int resourceType) { handleClientAreaChange(); // Send resize event to trigger desktopwidget workAreaResized signal - QResizeEvent e(qt_desktopWidget->size(), qt_desktopWidget->size()); - QApplication::sendEvent(qt_desktopWidget, &e); + if (qt_desktopWidget) { + QResizeEvent e(qt_desktopWidget->size(), qt_desktopWidget->size()); + QApplication::sendEvent(qt_desktopWidget, &e); + } break; } #endif -- cgit v0.12 From 2213f812acb023f7f52d930c30c0ea7a170629bf Mon Sep 17 00:00:00 2001 From: Sami Merila Date: Fri, 8 Apr 2011 10:07:16 +0300 Subject: GraphicsView is not reset if focusItem is not set when keyboard closes When splitview closes (i.e. keyboard is dismissed), application's graphicsview containing the input widget (focus item) is reset back to original graphicsview transformation. As a fix, resetTransform is always called, when rootItem is found from graphicsView. Task-number: QT-4858 Reviewed-by: Guoqing Zhang --- src/gui/inputmethod/qcoefepinputcontext_s60.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/gui/inputmethod/qcoefepinputcontext_s60.cpp b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp index 3b5290c..868565d 100644 --- a/src/gui/inputmethod/qcoefepinputcontext_s60.cpp +++ b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp @@ -410,12 +410,14 @@ void QCoeFepInputContext::resetSplitViewWidget(bool keepInputWidget) windowToMove->setUpdatesEnabled(false); if (!alwaysResize) { - if (gv->scene() && gv->scene()->focusItem()) { - // Check if the widget contains cursorPositionChanged signal and disconnect from it. - QByteArray signal = QMetaObject::normalizedSignature(SIGNAL(cursorPositionChanged())); - int index = gv->scene()->focusItem()->toGraphicsObject()->metaObject()->indexOfSignal(signal.right(signal.length() - 1)); - if (index != -1) - disconnect(gv->scene()->focusItem()->toGraphicsObject(), SIGNAL(cursorPositionChanged()), this, SLOT(translateInputWidget())); + if (gv->scene()) { + if (gv->scene()->focusItem()) { + // Check if the widget contains cursorPositionChanged signal and disconnect from it. + QByteArray signal = QMetaObject::normalizedSignature(SIGNAL(cursorPositionChanged())); + int index = gv->scene()->focusItem()->toGraphicsObject()->metaObject()->indexOfSignal(signal.right(signal.length() - 1)); + if (index != -1) + disconnect(gv->scene()->focusItem()->toGraphicsObject(), SIGNAL(cursorPositionChanged()), this, SLOT(translateInputWidget())); + } QGraphicsItem *rootItem = 0; foreach (QGraphicsItem *item, gv->scene()->items()) { -- cgit v0.12 From 57d886821ceae5adc989efee81b9c78508cac925 Mon Sep 17 00:00:00 2001 From: Sami Merila Date: Fri, 8 Apr 2011 11:20:35 +0300 Subject: Make QS60Style to support new Tab graphics in new Symbian releases In SR.11 there is a new theme graphics (with separate ID) for TabWidget tab shapes. Also, shapes are no longer set overlapped, but are side-by-side without any gaps. Earlier releases still use the existing graphics with overlapping. Task-number: QT-4762 Reviewed-by: Miikka Heikkinen --- src/gui/styles/qs60style.cpp | 30 ++++++++++++++++++++---------- src/gui/styles/qs60style_s60.cpp | 33 ++++++++++++++++++++++----------- 2 files changed, 42 insertions(+), 21 deletions(-) diff --git a/src/gui/styles/qs60style.cpp b/src/gui/styles/qs60style.cpp index 4b76985..585986d 100644 --- a/src/gui/styles/qs60style.cpp +++ b/src/gui/styles/qs60style.cpp @@ -1550,8 +1550,10 @@ void QS60Style::drawControl(ControlElement element, const QStyleOption *option, skinElement==QS60StylePrivate::SE_TabBarTabWestActive) { const int borderThickness = QS60StylePrivate::pixelMetric(PM_DefaultFrameWidth); - const int tabOverlap = - QS60StylePrivate::pixelMetric(PM_TabBarTabOverlap) - borderThickness; + int tabOverlap = pixelMetric(PM_TabBarTabOverlap); + if (tabOverlap > borderThickness) + tabOverlap -= borderThickness; + const bool usesScrollButtons = (widget) ? (qobject_cast(widget))->usesScrollButtons() : false; const int roomForScrollButton = @@ -1590,9 +1592,11 @@ void QS60Style::drawControl(ControlElement element, const QStyleOption *option, QStyleOptionTabV3 optionTab = *tab; QRect tr = optionTab.rect; const bool directionMirrored = (optionTab.direction == Qt::RightToLeft); - const int borderThickness = QS60StylePrivate::pixelMetric(PM_DefaultFrameWidth); - const int tabOverlap = - QS60StylePrivate::pixelMetric(PM_TabBarTabOverlap) - borderThickness; + const int borderThickness = + QS60StylePrivate::pixelMetric(PM_DefaultFrameWidth); + int tabOverlap = pixelMetric(PM_TabBarTabOverlap); + if (tabOverlap > borderThickness) + tabOverlap -= borderThickness; const bool usesScrollButtons = (widget) ? (qobject_cast(widget))->usesScrollButtons() : false; const int roomForScrollButton = @@ -2541,6 +2545,11 @@ int QS60Style::pixelMetric(PixelMetric metric, const QStyleOption *option, const //without having to define custom pixel metric metricValue *= 2; +#if defined(Q_WS_S60) + if (metric == PM_TabBarTabOverlap && (QSysInfo::s60Version() > QSysInfo::SV_S60_5_2)) + metricValue = 0; +#endif + return metricValue; } @@ -3015,10 +3024,11 @@ QRect QS60Style::subElementRect(SubElement element, const QStyleOption *opt, con ret = QCommonStyle::subElementRect(element, opt, widget); if (const QStyleOptionTabWidgetFrame *twf = qstyleoption_cast(opt)) { - const int tabOverlapNoBorder = - QS60StylePrivate::pixelMetric(PM_TabBarTabOverlap); - const int tabOverlap = - tabOverlapNoBorder - QS60StylePrivate::pixelMetric(PM_DefaultFrameWidth); + const int borderThickness = + QS60StylePrivate::pixelMetric(PM_DefaultFrameWidth); + int tabOverlap = pixelMetric(PM_TabBarTabOverlap); + if (tabOverlap > borderThickness) + tabOverlap -= borderThickness; const QTabWidget *tab = qobject_cast(widget); int gain = (tab) ? tabOverlap * tab->count() : 0; switch (twf->shape) { @@ -3036,7 +3046,7 @@ QRect QS60Style::subElementRect(SubElement element, const QStyleOption *opt, con if ((ret.right() + gain) > widget->rect().right()) gain = widget->rect().right() - ret.right(); ret.adjust(0, 0, gain, 0); - } + } } break; } diff --git a/src/gui/styles/qs60style_s60.cpp b/src/gui/styles/qs60style_s60.cpp index 6a7158c..dc64872 100644 --- a/src/gui/styles/qs60style_s60.cpp +++ b/src/gui/styles/qs60style_s60.cpp @@ -89,17 +89,25 @@ enum TSupportRelease { ES60_5_0 = 0x0004, ES60_5_1 = 0x0008, ES60_5_2 = 0x0010, + ES60_5_3 = 0x0020, ES60_3_X = ES60_3_1 | ES60_3_2, // Releases before Symbian Foundation ES60_PreSF = ES60_3_1 | ES60_3_2 | ES60_5_0, + // Releases before the S60 5.2 + ES60_Pre52 = ES60_3_1 | ES60_3_2 | ES60_5_0 | ES60_5_1, + // Releases before S60 5.3 + ES60_Pre53 = ES60_3_1 | ES60_3_2 | ES60_5_0 | ES60_5_1 | ES60_5_2, // Add all new releases here - ES60_All = ES60_3_1 | ES60_3_2 | ES60_5_0 | ES60_5_1 | ES60_5_2 + ES60_All = ES60_3_1 | ES60_3_2 | ES60_5_0 | ES60_5_1 | ES60_5_2 | ES60_5_3 }; typedef struct { - const TAknsItemID &skinID; - TDrawType drawType; - int supportInfo; + const TAknsItemID &skinID; // Determines default theme graphics ID. + TDrawType drawType; // Determines which native drawing routine is used to draw this item. + int supportInfo; // Defines the S60 versions that use the default graphics. + // These two, define new graphics that are used in releases other than partMapEntry.supportInfo defined releases. + // In general, these are given in numeric form to allow style compilation in earlier + // native releases that do not contain the new graphics. int newMajorSkinId; int newMinorSkinId; } partMapEntry; @@ -188,12 +196,14 @@ const partMapEntry QS60StyleModeSpecifics::m_partMap[] = { /* SP_QgnGrafScrollArrowLeft */ {KAknsIIDQgnGrafScrollArrowLeft, EDrawGulIcon, ES60_All, -1,-1}, /* SP_QgnGrafScrollArrowRight */ {KAknsIIDQgnGrafScrollArrowRight, EDrawGulIcon, ES60_All, -1,-1}, /* SP_QgnGrafScrollArrowUp */ {KAknsIIDQgnGrafScrollArrowUp, EDrawGulIcon, ES60_All, -1,-1}, - /* SP_QgnGrafTabActiveL */ {KAknsIIDQgnGrafTabActiveL, EDrawIcon, ES60_All, -1,-1}, - /* SP_QgnGrafTabActiveM */ {KAknsIIDQgnGrafTabActiveM, EDrawIcon, ES60_All, -1,-1}, - /* SP_QgnGrafTabActiveR */ {KAknsIIDQgnGrafTabActiveR, EDrawIcon, ES60_All, -1,-1}, - /* SP_QgnGrafTabPassiveL */ {KAknsIIDQgnGrafTabPassiveL, EDrawIcon, ES60_All, -1,-1}, - /* SP_QgnGrafTabPassiveM */ {KAknsIIDQgnGrafTabPassiveM, EDrawIcon, ES60_All, -1,-1}, - /* SP_QgnGrafTabPassiveR */ {KAknsIIDQgnGrafTabPassiveR, EDrawIcon, ES60_All, -1,-1}, + + // In S60 5.3 there is a new tab graphic + /* SP_QgnGrafTabActiveL */ {KAknsIIDQgnGrafTabActiveL, EDrawIcon, ES60_Pre53, EAknsMajorSkin, 0x2219}, //KAknsIIDQtgFrTabActiveNormalL + /* SP_QgnGrafTabActiveM */ {KAknsIIDQgnGrafTabActiveM, EDrawIcon, ES60_Pre53, EAknsMajorSkin, 0x221b}, //KAknsIIDQtgFrTabActiveNormalC + /* SP_QgnGrafTabActiveR */ {KAknsIIDQgnGrafTabActiveR, EDrawIcon, ES60_Pre53, EAknsMajorSkin, 0x221a}, //KAknsIIDQtgFrTabActiveNormalR + /* SP_QgnGrafTabPassiveL */ {KAknsIIDQgnGrafTabPassiveL, EDrawIcon, ES60_Pre53, EAknsMajorSkin, 0x2221}, //KAknsIIDQtgFrTabPassiveNormalL + /* SP_QgnGrafTabPassiveM */ {KAknsIIDQgnGrafTabPassiveM, EDrawIcon, ES60_Pre53, EAknsMajorSkin, 0x2223}, //KAknsIIDQtgFrTabPassiveNormalC + /* SP_QgnGrafTabPassiveR */ {KAknsIIDQgnGrafTabPassiveR, EDrawIcon, ES60_Pre53, EAknsMajorSkin, 0x2222}, //KAknsIIDQtgFrTabPassiveNormalR // In 3.1 there is no slider groove. /* SP_QgnGrafNsliderEndLeft */ {KAknsIIDNone, EDrawIcon, ES60_3_1, EAknsMajorGeneric, 0x19cf /* KAknsIIDQgnGrafNsliderEndLeft */}, @@ -1140,7 +1150,8 @@ bool QS60StyleModeSpecifics::checkSupport(const int supportedRelease) (currentRelease == QSysInfo::SV_S60_3_2 && supportedRelease & ES60_3_2) || (currentRelease == QSysInfo::SV_S60_5_0 && supportedRelease & ES60_5_0) || (currentRelease == QSysInfo::SV_S60_5_1 && supportedRelease & ES60_5_1) || - (currentRelease == QSysInfo::SV_S60_5_2 && supportedRelease & ES60_5_2)); + (currentRelease == QSysInfo::SV_S60_5_2 && supportedRelease & ES60_5_2) || + (currentRelease == QSysInfo::SV_S60_5_3 && supportedRelease & ES60_5_3) ); } TAknsItemID QS60StyleModeSpecifics::partSpecificThemeId(int part) -- cgit v0.12 From a84b6c258841492dde22a8370e6b40b28bc4f078 Mon Sep 17 00:00:00 2001 From: Guoqing Zhang Date: Fri, 8 Apr 2011 11:45:31 +0300 Subject: Add focus frame support in stylesheet Task-number: QTBUG-16027 Reviewed-by: Sami Merila --- src/gui/styles/qstylesheetstyle.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/gui/styles/qstylesheetstyle.cpp b/src/gui/styles/qstylesheetstyle.cpp index a4e7c38..6a0bf5e 100644 --- a/src/gui/styles/qstylesheetstyle.cpp +++ b/src/gui/styles/qstylesheetstyle.cpp @@ -3339,6 +3339,11 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q } break; + case CE_FocusFrame: + if (rule.hasBorder()) + rule.drawBorder(p, opt->rect); + return; + case CE_PushButton: if (const QStyleOptionButton *btn = qstyleoption_cast(opt)) { if (rule.hasDrawable() || rule.hasBox() || rule.hasPosition() || rule.hasPalette() || -- cgit v0.12 From de9dd35dd8dc7502fcb4bd94ec1bbf2ff2435a68 Mon Sep 17 00:00:00 2001 From: Liang Qi Date: Fri, 8 Apr 2011 15:03:50 +0200 Subject: Add the auto detection for OpenVG in configure Task-number: QTBUG-18647 Reviewed-by: axis --- configure | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configure b/configure index 4c8ac11..36402e5 100755 --- a/configure +++ b/configure @@ -641,10 +641,10 @@ CFG_XRANDR=runtime CFG_XRENDER=auto CFG_MITSHM=auto CFG_OPENGL=auto -CFG_OPENVG=no +CFG_OPENVG=auto CFG_OPENVG_LC_INCLUDES=no -CFG_OPENVG_SHIVA=no -CFG_OPENVG_ON_OPENGL=no +CFG_OPENVG_SHIVA=auto +CFG_OPENVG_ON_OPENGL=auto CFG_EGL=no CFG_EGL_GLES_INCLUDES=no CFG_SSE=auto -- cgit v0.12 From a951fb79139498774d021759d0466b4b2ff50e68 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Thu, 7 Apr 2011 11:25:08 +0100 Subject: QUdpSocket autotest updates 1. Start the default bearer, when Qt is built with bearer management 2. Allow server sockets to have IPv6 any addresses 3. Broadcasting test - broadcast on each valid broadcast address 4. Enable IPv6 tests on symbian 5. writeDatagram test - workaround symbian having a smaller recieve buffer for UDP packets than the maximum packet size it can send. 6. Add QEXPECT_FAIL for some multicast tests on symbian, the OS support for multicast is incomplete. 7. Choke the echo test, as the test server shuts down the echo service for 10 seconds when receiving packets too fast. 8. For manual testing, added the FORCE_SESSION macro to test behaviour of UDP sockets when they have an explicit network session associated Reviewed-by: Markus Goetz --- tests/auto/qudpsocket/tst_qudpsocket.cpp | 191 +++++++++++++++++++++++++++---- 1 file changed, 168 insertions(+), 23 deletions(-) diff --git a/tests/auto/qudpsocket/tst_qudpsocket.cpp b/tests/auto/qudpsocket/tst_qudpsocket.cpp index e6fe068..2c8049f 100644 --- a/tests/auto/qudpsocket/tst_qudpsocket.cpp +++ b/tests/auto/qudpsocket/tst_qudpsocket.cpp @@ -55,9 +55,15 @@ #include #include "../network-settings.h" +#ifndef QT_NO_BEARERMANAGEMENT +#include +#include +#include +#endif + Q_DECLARE_METATYPE(QHostAddress) Q_DECLARE_METATYPE(QNetworkInterface) - +Q_DECLARE_METATYPE(QSharedPointer) //TESTED_CLASS= //TESTED_FILES= @@ -114,6 +120,13 @@ private slots: protected slots: void empty_readyReadSlot(); void empty_connectedSlot(); + +private: +#ifndef QT_NO_BEARERMANAGEMENT + QNetworkConfigurationManager *netConfMan; + QNetworkConfiguration networkConfiguration; + QSharedPointer networkSession; +#endif }; tst_QUdpSocket::tst_QUdpSocket() @@ -132,6 +145,16 @@ void tst_QUdpSocket::initTestCase_data() QTest::newRow("WithoutProxy") << false << 0; QTest::newRow("WithSocks5Proxy") << true << int(QNetworkProxy::Socks5Proxy); + +#ifndef QT_NO_BEARERMANAGEMENT + netConfMan = new QNetworkConfigurationManager(this); + networkConfiguration = netConfMan->defaultConfiguration(); + networkSession = QSharedPointer(new QNetworkSession(networkConfiguration)); + if (!networkSession->isOpen()) { + networkSession->open(); + QVERIFY(networkSession->waitForOpened(30000)); + } +#endif } void tst_QUdpSocket::init() @@ -156,6 +179,9 @@ void tst_QUdpSocket::cleanup() void tst_QUdpSocket::constructing() { QUdpSocket socket; +#ifdef FORCE_SESSION + socket.setProperty("_q_networksession", QVariant::fromValue(networkSession)); +#endif QVERIFY(socket.isSequential()); QVERIFY(!socket.isOpen()); @@ -173,6 +199,9 @@ void tst_QUdpSocket::constructing() void tst_QUdpSocket::unconnectedServerAndClientTest() { QUdpSocket serverSocket; +#ifdef FORCE_SESSION + serverSocket.setProperty("_q_networksession", QVariant::fromValue(networkSession)); +#endif qRegisterMetaType("QAbstractSocket::SocketState"); @@ -183,11 +212,14 @@ void tst_QUdpSocket::unconnectedServerAndClientTest() const char *message[] = {"Yo mista", "Yo", "Wassap"}; QHostAddress serverAddress = QHostAddress::LocalHost; - if (!(serverSocket.localAddress() == QHostAddress::Any)) + if (!(serverSocket.localAddress() == QHostAddress::Any || serverSocket.localAddress() == QHostAddress::AnyIPv6)) serverAddress = serverSocket.localAddress(); for (int i = 0; i < 3; ++i) { QUdpSocket clientSocket; +#ifdef FORCE_SESSION + clientSocket.setProperty("_q_networksession", QVariant::fromValue(networkSession)); +#endif QCOMPARE(int(clientSocket.writeDatagram(message[i], strlen(message[i]), serverAddress, serverSocket.localPort())), int(strlen(message[i]))); @@ -218,8 +250,21 @@ void tst_QUdpSocket::broadcasting() #endif const char *message[] = {"Yo mista", "", "Yo", "Wassap"}; + QList broadcastAddresses; + foreach (QNetworkInterface iface, QNetworkInterface::allInterfaces()) { + if ((iface.flags() & QNetworkInterface::CanBroadcast) + && iface.flags() & QNetworkInterface::IsUp) { + for (int i=0;i("qint64"); qRegisterMetaType("QAbstractSocket::SocketError"); @@ -475,8 +552,16 @@ void tst_QUdpSocket::writeDatagram() QCOMPARE(*static_cast(bytesspy.at(0).at(0).constData()), qint64(i * 1024)); QCOMPARE(errorspy.count(), 0); - if (!server.waitForReadyRead(5000)) + if (!server.waitForReadyRead(5000)) { +#ifdef Q_OS_SYMBIAN + //symbian receive buffer for datagrams is ~30k, but it can send datagrams up to the maximum 64k... + if (i > 28) { + i = 64; + continue; + } +#endif QSKIP(QString("UDP packet lost at size %1, unable to complete the test.").arg(i * 1024).toLatin1().data(), SkipSingle); + } QCOMPARE(server.pendingDatagramSize(), qint64(i * 1024)); QCOMPARE(server.readDatagram(0, 0), qint64(0)); } @@ -501,14 +586,21 @@ void tst_QUdpSocket::performance() #endif // Q_OS_SYMBIAN QUdpSocket server; +#ifdef FORCE_SESSION + server.setProperty("_q_networksession", QVariant::fromValue(networkSession)); +#endif QVERIFY2(server.bind(), server.errorString().toLatin1().constData()); QHostAddress serverAddress = QHostAddress::LocalHost; - if (!(server.localAddress() == QHostAddress::Any)) + if (!(server.localAddress() == QHostAddress::Any || server.localAddress() == QHostAddress::AnyIPv6)) serverAddress = server.localAddress(); QUdpSocket client; +#ifdef FORCE_SESSION + client.setProperty("_q_networksession", QVariant::fromValue(networkSession)); +#endif client.connectToHost(serverAddress, server.localPort()); + QVERIFY(client.waitForConnected(10000)); QTime stopWatch; stopWatch.start(); @@ -548,8 +640,14 @@ void tst_QUdpSocket::bindMode() } QUdpSocket socket; +#ifdef FORCE_SESSION + socket.setProperty("_q_networksession", QVariant::fromValue(networkSession)); +#endif QVERIFY2(socket.bind(), socket.errorString().toLatin1().constData()); QUdpSocket socket2; +#ifdef FORCE_SESSION + socket2.setProperty("_q_networksession", QVariant::fromValue(networkSession)); +#endif QVERIFY(!socket2.bind(socket.localPort())); #if defined(Q_OS_SYMBIAN) if(RProcess().HasCapability(ECapabilityNetworkControl)) { @@ -619,16 +717,12 @@ void tst_QUdpSocket::writeDatagramToNonExistingPeer_data() QTest::addColumn("bind"); QTest::addColumn("peerAddress"); QHostAddress localhost(QHostAddress::LocalHost); -#if !defined(Q_OS_SYMBIAN) QHostAddress remote = QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().first(); -#endif QTest::newRow("localhost-unbound") << false << localhost; QTest::newRow("localhost-bound") << true << localhost; -#if !defined(Q_OS_SYMBIAN) QTest::newRow("remote-unbound") << false << remote; QTest::newRow("remote-bound") << true << remote; -#endif } void tst_QUdpSocket::writeDatagramToNonExistingPeer() @@ -639,6 +733,9 @@ void tst_QUdpSocket::writeDatagramToNonExistingPeer() quint16 peerPort = 33533 + int(bind); QUdpSocket sUdp; +#ifdef FORCE_SESSION + sUdp.setProperty("_q_networksession", QVariant::fromValue(networkSession)); +#endif QSignalSpy sReadyReadSpy(&sUdp, SIGNAL(readyRead())); if (bind) QVERIFY(sUdp.bind()); @@ -651,14 +748,10 @@ void tst_QUdpSocket::writeToNonExistingPeer_data() { QTest::addColumn("peerAddress"); QHostAddress localhost(QHostAddress::LocalHost); -#if !defined(Q_OS_SYMBIAN) QHostAddress remote = QHostInfo::fromName(QtNetworkSettings::serverName()).addresses().first(); -#endif // write (required to be connected) QTest::newRow("localhost") << localhost; -#if !defined(Q_OS_SYMBIAN) QTest::newRow("remote") << remote; -#endif } void tst_QUdpSocket::writeToNonExistingPeer() @@ -669,9 +762,13 @@ void tst_QUdpSocket::writeToNonExistingPeer() qRegisterMetaType("QAbstractSocket::SocketError"); QUdpSocket sConnected; +#ifdef FORCE_SESSION + sConnected.setProperty("_q_networksession", QVariant::fromValue(networkSession)); +#endif QSignalSpy sConnectedReadyReadSpy(&sConnected, SIGNAL(readyRead())); QSignalSpy sConnectedErrorSpy(&sConnected, SIGNAL(error(QAbstractSocket::SocketError))); sConnected.connectToHost(peerAddress, peerPort, QIODevice::ReadWrite); + QVERIFY(sConnected.waitForConnected(10000)); // the first write succeeds... QCOMPARE(sConnected.write("", 1), qint64(1)); @@ -845,12 +942,18 @@ void tst_QUdpSocket::zeroLengthDatagram() return; QUdpSocket receiver; +#ifdef FORCE_SESSION + receiver.setProperty("_q_networksession", QVariant::fromValue(networkSession)); +#endif QVERIFY(receiver.bind()); QVERIFY(!receiver.waitForReadyRead(100)); QVERIFY(!receiver.hasPendingDatagrams()); QUdpSocket sender; +#ifdef FORCE_SESSION + sender.setProperty("_q_networksession", QVariant::fromValue(networkSession)); +#endif QCOMPARE(sender.writeDatagram(QByteArray(), QHostAddress::LocalHost, receiver.localPort()), qint64(0)); QVERIFY(receiver.waitForReadyRead(1000)); @@ -892,6 +995,9 @@ void tst_QUdpSocket::multicastTtlOption() } QUdpSocket udpSocket; +#ifdef FORCE_SESSION + udpSocket.setProperty("_q_networksession", QVariant::fromValue(networkSession)); +#endif // bind, but ignore the result, we are only interested in initializing the socket (void) udpSocket.bind(bindAddress, 0); udpSocket.setSocketOption(QUdpSocket::MulticastTtlOption, ttl); @@ -931,6 +1037,9 @@ void tst_QUdpSocket::multicastLoopbackOption() } QUdpSocket udpSocket; +#ifdef FORCE_SESSION + udpSocket.setProperty("_q_networksession", QVariant::fromValue(networkSession)); +#endif // bind, but ignore the result, we are only interested in initializing the socket (void) udpSocket.bind(bindAddress, 0); udpSocket.setSocketOption(QUdpSocket::MulticastLoopbackOption, loopback); @@ -951,6 +1060,9 @@ void tst_QUdpSocket::multicastJoinBeforeBind() QFETCH(QHostAddress, groupAddress); QUdpSocket udpSocket; +#ifdef FORCE_SESSION + udpSocket.setProperty("_q_networksession", QVariant::fromValue(networkSession)); +#endif // cannot join group before binding QTest::ignoreMessage(QtWarningMsg, "QUdpSocket::joinMulticastGroup() called on a QUdpSocket when not in QUdpSocket::BoundState"); QVERIFY(!udpSocket.joinMulticastGroup(groupAddress)); @@ -972,8 +1084,16 @@ void tst_QUdpSocket::multicastLeaveAfterClose() } QUdpSocket udpSocket; +#ifdef FORCE_SESSION + udpSocket.setProperty("_q_networksession", QVariant::fromValue(networkSession)); +#endif +#ifdef Q_OS_SYMBIAN + QVERIFY2(udpSocket.bind(), + qPrintable(udpSocket.errorString())); +#else QVERIFY2(udpSocket.bind(groupAddress, 0), qPrintable(udpSocket.errorString())); +#endif QVERIFY2(udpSocket.joinMulticastGroup(groupAddress), qPrintable(udpSocket.errorString())); udpSocket.close(); @@ -997,6 +1117,9 @@ void tst_QUdpSocket::setMulticastInterface_data() void tst_QUdpSocket::setMulticastInterface() { +#ifdef Q_OS_SYMBIAN + QSKIP("Symbian has no IPV6_MULTICAST_IF equivalent", SkipAll); +#else QFETCH_GLOBAL(bool, setProxy); QFETCH(QNetworkInterface, iface); QFETCH(QHostAddress, address); @@ -1019,6 +1142,7 @@ void tst_QUdpSocket::setMulticastInterface() } else { QVERIFY(!iface2.isValid()); } +#endif } void tst_QUdpSocket::multicast_data() @@ -1058,8 +1182,17 @@ void tst_QUdpSocket::multicast() } QUdpSocket receiver; +#ifdef FORCE_SESSION + receiver.setProperty("_q_networksession", QVariant::fromValue(networkSession)); +#endif // bind first, then verify that we can join the multicast group +#ifdef Q_OS_SYMBIAN + if (!setProxy) { + QEXPECT_FAIL("same bind, group ipv4 address", "bind to group address not supported on symbian", Abort); + QEXPECT_FAIL("same bind, group ipv6 address", "bind to group address not supported on symbian", Abort); + } +#endif QVERIFY2(receiver.bind(bindAddress, 0) == bindResult, qPrintable(receiver.errorString())); if (!bindResult) @@ -1077,6 +1210,10 @@ void tst_QUdpSocket::multicast() << QByteArray("cdef"); QUdpSocket sender; +#ifdef FORCE_SESSION + sender.setProperty("_q_networksession", QVariant::fromValue(networkSession)); +#endif + sender.bind(); foreach (const QByteArray &datagram, datagrams) { QCOMPARE(int(sender.writeDatagram(datagram, groupAddress, receiver.localPort())), int(datagram.size())); @@ -1092,6 +1229,9 @@ void tst_QUdpSocket::multicast() receiver.readDatagram(datagram.data(), datagram.size(), 0, 0); receivedDatagrams << datagram; } +#ifdef Q_OS_SYMBIAN + QEXPECT_FAIL("valid bind, group ipv4 address", "IPv4 multicast not supported on symbian", Abort); +#endif QCOMPARE(receivedDatagrams, datagrams); QVERIFY2(receiver.leaveMulticastGroup(groupAddress), qPrintable(receiver.errorString())); @@ -1112,15 +1252,19 @@ void tst_QUdpSocket::echo() QHostAddress remote = info.addresses().first(); QUdpSocket sock; +#ifdef FORCE_SESSION + sock.setProperty("_q_networksession", QVariant::fromValue(networkSession)); +#endif if (connect) { sock.connectToHost(remote, 7); + QVERIFY(sock.waitForConnected(10000)); } else { sock.bind(); } QByteArray out(30, 'x'); QByteArray in; int successes = 0; - for (int i=0;i<20;i++) { + for (int i=0;i<10;i++) { if (connect) { sock.write(out); } else { @@ -1143,8 +1287,9 @@ void tst_QUdpSocket::echo() if (!sock.isValid()) QFAIL(sock.errorString().toLatin1().constData()); qDebug() << "packets in" << successes << "out" << i; + QTest::qWait(50); //choke to avoid triggering flood/DDoS protections on echo service } - QVERIFY(successes >= 18); + QVERIFY(successes >= 9); } QTEST_MAIN(tst_QUdpSocket) -- cgit v0.12 From 847df81a5680fe4d71196d0afe5e68e41ae49700 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Thu, 7 Apr 2011 15:10:31 +0100 Subject: Implement support for sockets started before the event loop If there is no event loop when a socket notification is enabled, then invoke the method via a queued connection so that it is run again when the event loop is started. This covers sockets created and having an asynchronous API called before calling QCoreApplication::exec(). Reviewed-by: Markus Goetz --- src/network/socket/qsymbiansocketengine.cpp | 69 +++++++++++------------------ src/network/socket/qsymbiansocketengine_p.h | 2 +- tests/auto/qtcpsocket/tst_qtcpsocket.cpp | 45 ++++++++++++++++++- 3 files changed, 72 insertions(+), 44 deletions(-) diff --git a/src/network/socket/qsymbiansocketengine.cpp b/src/network/socket/qsymbiansocketengine.cpp index 165316d..f1b2982 100644 --- a/src/network/socket/qsymbiansocketengine.cpp +++ b/src/network/socket/qsymbiansocketengine.cpp @@ -1433,6 +1433,26 @@ void QSymbianSocketEnginePrivate::setError(TInt symbianError) hasSetSocketError = true; } +void QSymbianSocketEngine::startNotifications() +{ + Q_D(QSymbianSocketEngine); +#ifdef QNATIVESOCKETENGINE_DEBUG + qDebug() << "QSymbianSocketEngine::startNotifications" << d->readNotificationsEnabled << d->writeNotificationsEnabled << d->exceptNotificationsEnabled; +#endif + if (!d->asyncSelect && (d->readNotificationsEnabled || d->writeNotificationsEnabled || d->exceptNotificationsEnabled)) { + if (d->threadData->eventDispatcher) { + d->asyncSelect = q_check_ptr(new QAsyncSelect( + static_cast (d->threadData->eventDispatcher), d->nativeSocket, + this)); + } else { + // call again when event dispatcher has been created + QMetaObject::invokeMethod(this, "startNotifications", Qt::QueuedConnection); + } + } + if (d->asyncSelect) + d->asyncSelect->IssueRequest(); +} + bool QSymbianSocketEngine::isReadNotificationEnabled() const { Q_D(const QSymbianSocketEngine); @@ -1448,13 +1468,7 @@ void QSymbianSocketEngine::setReadNotificationEnabled(bool enable) qDebug() << "QSymbianSocketEngine::setReadNotificationEnabled" << enable << "socket" << d->socketDescriptor; #endif d->readNotificationsEnabled = enable; - if (enable && d->threadData->eventDispatcher && !d->asyncSelect) - d->asyncSelect = q_check_ptr( - new QAsyncSelect(static_cast(d->threadData->eventDispatcher), - d->nativeSocket, this)); - // TODO: what do we do if event dispatcher doesn't exist yet? - if (d->asyncSelect) - d->asyncSelect->IssueRequest(); + startNotifications(); } bool QSymbianSocketEngine::isWriteNotificationEnabled() const @@ -1472,13 +1486,7 @@ void QSymbianSocketEngine::setWriteNotificationEnabled(bool enable) qDebug() << "QSymbianSocketEngine::setWriteNotificationEnabled" << enable << "socket" << d->socketDescriptor; #endif d->writeNotificationsEnabled = enable; - if (enable && d->threadData->eventDispatcher && !d->asyncSelect) - d->asyncSelect = q_check_ptr( - new QAsyncSelect(static_cast(d->threadData->eventDispatcher), - d->nativeSocket, this)); - // TODO: what do we do if event dispatcher doesn't exist yet? - if (d->asyncSelect) - d->asyncSelect->IssueRequest(); + startNotifications(); } bool QSymbianSocketEngine::isExceptionNotificationEnabled() const @@ -1489,7 +1497,6 @@ bool QSymbianSocketEngine::isExceptionNotificationEnabled() const return false; } -// FIXME do we really need this for symbian? void QSymbianSocketEngine::setExceptionNotificationEnabled(bool enable) { Q_D(QSymbianSocketEngine); @@ -1498,12 +1505,7 @@ void QSymbianSocketEngine::setExceptionNotificationEnabled(bool enable) qDebug() << "QSymbianSocketEngine::setExceptionNotificationEnabled" << enable << "socket" << d->socketDescriptor; #endif d->exceptNotificationsEnabled = enable; - if (enable && d->threadData->eventDispatcher && !d->asyncSelect) - d->asyncSelect = q_check_ptr( - new QAsyncSelect(static_cast(d->threadData->eventDispatcher), - d->nativeSocket, this)); - if (d->asyncSelect) - d->asyncSelect->IssueRequest(); + startNotifications(); } bool QSymbianSocketEngine::waitForRead(int msecs, bool *timedOut) @@ -1588,38 +1590,21 @@ qint64 QSymbianSocketEngine::bytesToWrite() const return 0; } -//TODO: is defining PostThreadChangeEvent as QEvent::User + 1 safe? -//TODO: would QMetaObject::invokeMethod(obj, "postThreadChangeSlot", Qt::QueuedConnection) be better? -//TODO: if QTBUG-16787 is implemented, use that instead bool QSymbianSocketEngine::event(QEvent* ev) { Q_D(QSymbianSocketEngine); + if (ev->type() == QEvent::ThreadChange) { #ifdef QNATIVESOCKETENGINE_DEBUG - qDebug() << "QSymbianSocketEngine::event"; -#endif - switch (ev->type()) { - case QEvent::ThreadChange: -#ifdef QNATIVESOCKETENGINE_DEBUG - qDebug() << "ThreadChange" << d->readNotificationsEnabled << d->writeNotificationsEnabled << d->exceptNotificationsEnabled; + qDebug() << "QSymbianSocketEngine::event - ThreadChange" << d->readNotificationsEnabled << d->writeNotificationsEnabled << d->exceptNotificationsEnabled; #endif if (d->asyncSelect) { delete d->asyncSelect; d->asyncSelect = 0; - QEvent *postThreadChangeEvent = new QEvent(PostThreadChangeEvent); - QCoreApplication::postEvent(this, postThreadChangeEvent); + // recreate select in new thread (because it is queued, the method is called in the new thread context) + QMetaObject::invokeMethod(this, "startNotifications", Qt::QueuedConnection); } d->selectTimer.Close(); return true; - case PostThreadChangeEvent: -#ifdef QNATIVESOCKETENGINE_DEBUG - qDebug() << "PostThreadChangeEvent" << d->readNotificationsEnabled << d->writeNotificationsEnabled << d->exceptNotificationsEnabled; -#endif - // recreate select in new thread - d->asyncSelect = q_check_ptr( - new QAsyncSelect(static_cast(d->threadData->eventDispatcher), - d->nativeSocket, this)); - d->asyncSelect->IssueRequest(); - return true; } return QAbstractSocketEngine::event(ev); } diff --git a/src/network/socket/qsymbiansocketengine_p.h b/src/network/socket/qsymbiansocketengine_p.h index bbe1269..85ab54a 100644 --- a/src/network/socket/qsymbiansocketengine_p.h +++ b/src/network/socket/qsymbiansocketengine_p.h @@ -134,7 +134,7 @@ public: bool event(QEvent* ev); - static const QEvent::Type PostThreadChangeEvent = (QEvent::Type)(QEvent::User + 1); + Q_INVOKABLE void startNotifications(); public Q_SLOTS: // TODO: Why do we do this? This is private Qt implementation stuff anyway, no need for it diff --git a/tests/auto/qtcpsocket/tst_qtcpsocket.cpp b/tests/auto/qtcpsocket/tst_qtcpsocket.cpp index 6852e29..623e02b 100644 --- a/tests/auto/qtcpsocket/tst_qtcpsocket.cpp +++ b/tests/auto/qtcpsocket/tst_qtcpsocket.cpp @@ -106,6 +106,7 @@ Q_DECLARE_METATYPE(QList) //TESTED_FILES= QT_FORWARD_DECLARE_CLASS(QTcpSocket) +QT_FORWARD_DECLARE_CLASS(SocketPair) class tst_QTcpSocket : public QObject { @@ -138,6 +139,7 @@ public slots: void init(); void cleanup(); private slots: + void socketsConstructedBeforeEventLoop(); void constructing(); void setInvalidSocketDescriptor(); void setSocketDescriptor(); @@ -221,6 +223,8 @@ protected slots: void abortiveClose_abortSlot(); void remoteCloseErrorSlot(); void proxyAuthenticationRequired(const QNetworkProxy &, QAuthenticator *auth); + void earlySocketBytesSent(qint64 bytes); + void earlySocketReadyRead(); private: QByteArray expectedReplyIMAP(); @@ -243,6 +247,10 @@ private: bool gotClosedSignal; int numConnections; static int loopLevel; + + SocketPair *earlyConstructedSockets; + int earlyBytesWrittenCount; + int earlyReadyReadCount; }; enum ProxyTests { @@ -296,8 +304,16 @@ public: tst_QTcpSocket::tst_QTcpSocket() { - Q_SET_DEFAULT_IAP tmpSocket = 0; + + //This code relates to the socketsConstructedBeforeEventLoop test case + earlyConstructedSockets = new SocketPair; + QVERIFY(earlyConstructedSockets->create()); + earlyBytesWrittenCount = 0; + earlyReadyReadCount = 0; + connect(earlyConstructedSockets->endPoints[0], SIGNAL(readyRead()), this, SLOT(earlySocketReadyRead())); + connect(earlyConstructedSockets->endPoints[1], SIGNAL(bytesWritten(qint64)), this, SLOT(earlySocketBytesSent(qint64))); + earlyConstructedSockets->endPoints[1]->write("hello work"); } tst_QTcpSocket::~tst_QTcpSocket() @@ -399,6 +415,33 @@ void tst_QTcpSocket::proxyAuthenticationRequired(const QNetworkProxy &, QAuthent //---------------------------------------------------------------------------------- +void tst_QTcpSocket::socketsConstructedBeforeEventLoop() +{ + QFETCH_GLOBAL(bool, setProxy); + QFETCH_GLOBAL(bool, ssl); + if (setProxy || ssl) + return; + //This test checks that sockets constructed before QCoreApplication::exec() still emit signals + //see construction code in the tst_QTcpSocket constructor + enterLoop(3); + QCOMPARE(earlyBytesWrittenCount, 1); + QCOMPARE(earlyReadyReadCount, 1); + earlyConstructedSockets->endPoints[0]->close(); + earlyConstructedSockets->endPoints[1]->close(); +} + +void tst_QTcpSocket::earlySocketBytesSent(qint64 bytes) +{ + earlyBytesWrittenCount++; +} + +void tst_QTcpSocket::earlySocketReadyRead() +{ + earlyReadyReadCount++; +} + +//---------------------------------------------------------------------------------- + void tst_QTcpSocket::constructing() { QTcpSocket *socket = newSocket(); -- cgit v0.12 From 0f7a4790bb0e3435a02f8751a29dc06c1f88d8d5 Mon Sep 17 00:00:00 2001 From: Sami Merila Date: Mon, 11 Apr 2011 13:48:35 +0300 Subject: tst_QStyle::drawItemPixmap test case fails on Symbian^3 The autotest assumes that created QPixmap are exactly same irregardless how the pixmaps were created. However, there is no guarantee that pixmaps that look the same (i.e. in this case green rectangles) are "same". QPixmap is platform dependent and might have e.g. optimized format in some of the platforms. Task-number: QT-4805 Reviewed-by: Jani Hautakangas --- tests/auto/qstyle/tst_qstyle.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/auto/qstyle/tst_qstyle.cpp b/tests/auto/qstyle/tst_qstyle.cpp index ad5d7ff..5c319f0 100644 --- a/tests/auto/qstyle/tst_qstyle.cpp +++ b/tests/auto/qstyle/tst_qstyle.cpp @@ -272,6 +272,18 @@ void tst_QStyle::drawItemPixmap() QPixmap p(QString(SRCDIR) + "/task_25863.png", "PNG"); QPixmap actualPix = QPixmap::grabWidget(testWidget); + +#ifdef Q_OS_SYMBIAN + // QPixmap cannot be assumed to be exactly same, unless it is created from exactly same content. + // In Symbian, pixmap format might get "optimized" depending on how QPixmap is created. + // Therefore, force the content to specific format and compare QImages. + // Then re-create the QPixmaps and compare those. + QImage i1 = p.toImage().convertToFormat(QImage::Format_ARGB32_Premultiplied); + p = QPixmap::fromImage(i1); + QImage i2 = actualPix.toImage().convertToFormat(QImage::Format_ARGB32_Premultiplied); + actualPix = QPixmap::fromImage(i2); + QVERIFY(i1 == i2); +#endif QVERIFY(pixmapsAreEqual(&actualPix,&p)); testWidget->hide(); } -- cgit v0.12 From e2ac68f3437ab6e9e865c7c9ad1c52b293f61910 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 23 Mar 2011 20:05:49 +0100 Subject: fix detection of relative location information an empty line number does not indicate relative loc info - it may be the result of -no-ui-lines. instead, an empty file name does indicate it - no file name at all makes no sense, so this means a previous messages has set it already. and we need this additional detection, as the entire ts file may have no line number info to base the decision on at all. --- tools/linguist/shared/ts.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tools/linguist/shared/ts.cpp b/tools/linguist/shared/ts.cpp index 85be5c6..4523bc5 100644 --- a/tools/linguist/shared/ts.cpp +++ b/tools/linguist/shared/ts.cpp @@ -264,6 +264,7 @@ bool TSReader::read(Translator &translator) //qDebug() << "TS " << attributes(); QHash currentLine; QString currentFile; + bool maybeRelative = false, maybeAbsolute = false; QXmlStreamAttributes atts = attributes(); //QString version = atts.value(strversion).toString(); @@ -342,10 +343,12 @@ bool TSReader::read(Translator &translator) msg.setTranslatorComment(readContents()); } else if (elementStarts(strlocation)) { // + maybeAbsolute = true; QXmlStreamAttributes atts = attributes(); QString fileName = atts.value(strfilename).toString(); if (fileName.isEmpty()) { fileName = currentMsgFile; + maybeRelative = true; } else { if (refs.isEmpty()) currentFile = fileName; @@ -353,7 +356,6 @@ bool TSReader::read(Translator &translator) } const QString lin = atts.value(strline).toString(); if (lin.isEmpty()) { - translator.setLocationsType(Translator::RelativeLocations); refs.append(TranslatorMessage::Reference(fileName, -1)); } else { bool bOK; @@ -361,9 +363,7 @@ bool TSReader::read(Translator &translator) if (bOK) { if (lin.startsWith(QLatin1Char('+')) || lin.startsWith(QLatin1Char('-'))) { lineNo = (currentLine[fileName] += lineNo); - translator.setLocationsType(Translator::RelativeLocations); - } else { - translator.setLocationsType(Translator::AbsoluteLocations); + maybeRelative = true; } refs.append(TranslatorMessage::Reference(fileName, lineNo)); } @@ -422,6 +422,9 @@ bool TSReader::read(Translator &translator) } else { handleError(); } + translator.setLocationsType(maybeRelative ? Translator::RelativeLocations : + maybeAbsolute ? Translator::AbsoluteLocations : + Translator::NoLocations); } // } else { handleError(); @@ -727,7 +730,6 @@ bool saveTS(const Translator &translator, QIODevice &dev, ConversionData &cd, in bool loadTS(Translator &translator, QIODevice &dev, ConversionData &cd) { - translator.setLocationsType(Translator::NoLocations); TSReader reader(dev, cd); return reader.read(translator); } -- cgit v0.12 From 3bc0d853a09ae55c158946a99284a47b0b30a3b4 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Tue, 12 Apr 2011 11:36:37 +1000 Subject: Fix regression in wigglytext.qml This change re-adds the code removed in 8e9c28eaa4d7a3372b9a9a21a984701b62f96456 (which caused this regression), while keeping the new code as well (to specially handle the case of registration in componentCompleted()). Change-Id: I707e3d2ead9ea25079f79cd5e5886d1dc1c69d1b Task-number: QTBUG-18362 Reviewed-by: Aaron Kennedy --- src/declarative/qml/qdeclarativecomponent.cpp | 17 +++++++++++++++ src/declarative/qml/qdeclarativecomponent_p.h | 1 + .../data/delayedRegistration.qml | 25 ++++++++++++++++++++++ .../tst_qdeclarativebehaviors.cpp | 18 ++++++++++++++++ 4 files changed, 61 insertions(+) create mode 100644 tests/auto/declarative/qdeclarativebehaviors/data/delayedRegistration.qml diff --git a/src/declarative/qml/qdeclarativecomponent.cpp b/src/declarative/qml/qdeclarativecomponent.cpp index fc393d1..ac683a7 100644 --- a/src/declarative/qml/qdeclarativecomponent.cpp +++ b/src/declarative/qml/qdeclarativecomponent.cpp @@ -880,6 +880,7 @@ QObject * QDeclarativeComponentPrivate::begin(QDeclarativeContextData *parentCon state->bindValues = enginePriv->bindValues; state->parserStatus = enginePriv->parserStatus; + state->finalizedParserStatus = enginePriv->finalizedParserStatus; state->componentAttached = enginePriv->componentAttached; if (state->componentAttached) state->componentAttached->prev = &state->componentAttached; @@ -887,6 +888,7 @@ QObject * QDeclarativeComponentPrivate::begin(QDeclarativeContextData *parentCon enginePriv->componentAttached = 0; enginePriv->bindValues.clear(); enginePriv->parserStatus.clear(); + enginePriv->finalizedParserStatus.clear(); state->completePending = true; enginePriv->inProgressCreations++; } @@ -917,6 +919,7 @@ void QDeclarativeComponentPrivate::beginDeferred(QDeclarativeEnginePrivate *engi state->bindValues = enginePriv->bindValues; state->parserStatus = enginePriv->parserStatus; + state->finalizedParserStatus = enginePriv->finalizedParserStatus; state->componentAttached = enginePriv->componentAttached; if (state->componentAttached) state->componentAttached->prev = &state->componentAttached; @@ -924,6 +927,7 @@ void QDeclarativeComponentPrivate::beginDeferred(QDeclarativeEnginePrivate *engi enginePriv->componentAttached = 0; enginePriv->bindValues.clear(); enginePriv->parserStatus.clear(); + enginePriv->finalizedParserStatus.clear(); state->completePending = true; enginePriv->inProgressCreations++; } @@ -961,6 +965,18 @@ void QDeclarativeComponentPrivate::complete(QDeclarativeEnginePrivate *enginePri QDeclarativeEnginePrivate::clear(ps); } + for (int ii = 0; ii < state->finalizedParserStatus.count(); ++ii) { + QPair, int> status = state->finalizedParserStatus.at(ii); + QObject *obj = status.first; + if (obj) { + void *args[] = { 0 }; + QMetaObject::metacall(obj, QMetaObject::InvokeMetaMethod, + status.second, args); + } + } + + //componentComplete() can register additional finalization objects + //that are then never handled. Handle them manually here. if (1 == enginePriv->inProgressCreations) { for (int ii = 0; ii < enginePriv->finalizedParserStatus.count(); ++ii) { QPair, int> status = enginePriv->finalizedParserStatus.at(ii); @@ -986,6 +1002,7 @@ void QDeclarativeComponentPrivate::complete(QDeclarativeEnginePrivate *enginePri state->bindValues.clear(); state->parserStatus.clear(); + state->finalizedParserStatus.clear(); state->completePending = false; enginePriv->inProgressCreations--; diff --git a/src/declarative/qml/qdeclarativecomponent_p.h b/src/declarative/qml/qdeclarativecomponent_p.h index 020c5e0..f8bec2b 100644 --- a/src/declarative/qml/qdeclarativecomponent_p.h +++ b/src/declarative/qml/qdeclarativecomponent_p.h @@ -101,6 +101,7 @@ public: ConstructionState() : componentAttached(0), completePending(false) {} QList > bindValues; QList > parserStatus; + QList, int> > finalizedParserStatus; QDeclarativeComponentAttached *componentAttached; QList errors; bool completePending; diff --git a/tests/auto/declarative/qdeclarativebehaviors/data/delayedRegistration.qml b/tests/auto/declarative/qdeclarativebehaviors/data/delayedRegistration.qml new file mode 100644 index 0000000..aa384c3 --- /dev/null +++ b/tests/auto/declarative/qdeclarativebehaviors/data/delayedRegistration.qml @@ -0,0 +1,25 @@ +import QtQuick 1.0 + +Rectangle { + id: container + + width: 400; height: 400; + property Item myItem + + function doCreate() { + myItem = myComponent.createObject(container) + myItem.x = 100 + } + + Component { + id: myComponent + Rectangle { + width: 100 + height: 100 + color: "green" + Behavior on x { NumberAnimation { duration: 500 } } + } + } + + Component.onCompleted: doCreate() +} diff --git a/tests/auto/declarative/qdeclarativebehaviors/tst_qdeclarativebehaviors.cpp b/tests/auto/declarative/qdeclarativebehaviors/tst_qdeclarativebehaviors.cpp index 80ba907..4536d9e 100644 --- a/tests/auto/declarative/qdeclarativebehaviors/tst_qdeclarativebehaviors.cpp +++ b/tests/auto/declarative/qdeclarativebehaviors/tst_qdeclarativebehaviors.cpp @@ -81,6 +81,7 @@ private slots: void groupedPropertyCrash(); void runningTrue(); void sameValue(); + void delayedRegistration(); }; void tst_qdeclarativebehaviors::simpleBehavior() @@ -412,6 +413,23 @@ void tst_qdeclarativebehaviors::sameValue() QTRY_VERIFY(target->x() != qreal(0) && target->x() != qreal(100)); } +//QTBUG-18362 +void tst_qdeclarativebehaviors::delayedRegistration() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent c(&engine, SRCDIR "/data/delayedRegistration.qml"); + QDeclarativeRectangle *rect = qobject_cast(c.create()); + QVERIFY(rect != 0); + + QDeclarativeItem *innerRect = rect->property("myItem").value(); + QVERIFY(innerRect != 0); + + QCOMPARE(innerRect->property("x").toInt(), int(0)); + + QTRY_COMPARE(innerRect->property("x").toInt(), int(100)); +} + QTEST_MAIN(tst_qdeclarativebehaviors) #include "tst_qdeclarativebehaviors.moc" -- cgit v0.12 From ddae2b67a8eab5e6b298ce516234f4bf7c0367c1 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Tue, 12 Apr 2011 14:51:19 +1000 Subject: Ensure view is positioned correctly when orientation changes. Change-Id: I7fbedff965ae8c89dcbb96ba5dcee85c07aa29b1 Task-number: QTBUG-17065 Reviewed-by: Bea Lam --- .../graphicsitems/qdeclarativelistview.cpp | 2 + .../qdeclarativelistview/data/orientchange.qml | 7 ++++ .../tst_qdeclarativelistview.cpp | 47 ++++++++++++++++++++++ 3 files changed, 56 insertions(+) create mode 100644 tests/auto/declarative/qdeclarativelistview/data/orientchange.qml diff --git a/src/declarative/graphicsitems/qdeclarativelistview.cpp b/src/declarative/graphicsitems/qdeclarativelistview.cpp index f176916..4da45d1 100644 --- a/src/declarative/graphicsitems/qdeclarativelistview.cpp +++ b/src/declarative/graphicsitems/qdeclarativelistview.cpp @@ -2119,9 +2119,11 @@ void QDeclarativeListView::setOrientation(QDeclarativeListView::Orientation orie if (d->orient == QDeclarativeListView::Vertical) { setContentWidth(-1); setFlickableDirection(VerticalFlick); + setContentX(0); } else { setContentHeight(-1); setFlickableDirection(HorizontalFlick); + setContentY(0); } d->regenerate(); emit orientationChanged(); diff --git a/tests/auto/declarative/qdeclarativelistview/data/orientchange.qml b/tests/auto/declarative/qdeclarativelistview/data/orientchange.qml new file mode 100644 index 0000000..c7aa0cd --- /dev/null +++ b/tests/auto/declarative/qdeclarativelistview/data/orientchange.qml @@ -0,0 +1,7 @@ +import QtQuick 1.0 + +ListView { + width: 240; height: 320 + delegate: Rectangle { objectName: "wrapper"; width: 80; height: 80 } + model: 100 +} diff --git a/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp b/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp index 2267a89..ec60e8a 100644 --- a/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp +++ b/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp @@ -119,6 +119,7 @@ private slots: void testQtQuick11Attributes_data(); void rightToLeft(); void test_mirroring(); + void orientationChange(); private: template void items(); @@ -2583,6 +2584,52 @@ void tst_QDeclarativeListView::test_mirroring() delete canvasB; } +void tst_QDeclarativeListView::orientationChange() +{ + QDeclarativeView *canvas = createView(); + + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/orientchange.qml")); + qApp->processEvents(); + + QDeclarativeListView *listview = qobject_cast(canvas->rootObject()); + QVERIFY(listview != 0); + + QDeclarativeItem *contentItem = listview->contentItem(); + QVERIFY(contentItem != 0); + + listview->positionViewAtIndex(50, QDeclarativeListView::Beginning); + + // Confirm items positioned correctly + for (int i = 50; i < 54; ++i) { + QDeclarativeItem *item = findItem(contentItem, "wrapper", i); + QVERIFY(item); + QCOMPARE(item->y(), i*80.0); + } + + listview->setOrientation(QDeclarativeListView::Horizontal); + QCOMPARE(listview->contentY(), 0.); + + // Confirm items positioned correctly + for (int i = 0; i < 3; ++i) { + QDeclarativeItem *item = findItem(contentItem, "wrapper", i); + QVERIFY(item); + QCOMPARE(item->x(), i*80.0); + } + + listview->positionViewAtIndex(50, QDeclarativeListView::Beginning); + listview->setOrientation(QDeclarativeListView::Vertical); + QCOMPARE(listview->contentX(), 0.); + // + // Confirm items positioned correctly + for (int i = 0; i < 4; ++i) { + QDeclarativeItem *item = findItem(contentItem, "wrapper", i); + QVERIFY(item); + QCOMPARE(item->y(), i*80.0); + } + + delete canvas; +} + void tst_QDeclarativeListView::qListModelInterface_items() { items(); -- cgit v0.12 From c17150344510fc5fe239e39e6659bd16579586e8 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Tue, 12 Apr 2011 15:09:48 +1000 Subject: ListView has wrong keyPressEvent behaviour when vertical Regression intorduced by RTL changes. Change-Id: I272d07cd21d04f3e534aa183b1b10fcc8d062b79 Task-number: QTBUG-18581 Reviewed-by: Bea Lam --- src/declarative/graphicsitems/qdeclarativelistview.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/declarative/graphicsitems/qdeclarativelistview.cpp b/src/declarative/graphicsitems/qdeclarativelistview.cpp index 4da45d1..cb751f6 100644 --- a/src/declarative/graphicsitems/qdeclarativelistview.cpp +++ b/src/declarative/graphicsitems/qdeclarativelistview.cpp @@ -2770,7 +2770,7 @@ void QDeclarativeListView::keyPressEvent(QKeyEvent *event) return; if (d->model && d->model->count() && d->interactive) { - if ((!d->isRightToLeft() && event->key() == Qt::Key_Left) + if ((d->orient == QDeclarativeListView::Horizontal && !d->isRightToLeft() && event->key() == Qt::Key_Left) || (d->orient == QDeclarativeListView::Horizontal && d->isRightToLeft() && event->key() == Qt::Key_Right) || (d->orient == QDeclarativeListView::Vertical && event->key() == Qt::Key_Up)) { if (currentIndex() > 0 || (d->wrap && !event->isAutoRepeat())) { @@ -2781,7 +2781,7 @@ void QDeclarativeListView::keyPressEvent(QKeyEvent *event) event->accept(); return; } - } else if ((!d->isRightToLeft() && event->key() == Qt::Key_Right) + } else if ((d->orient == QDeclarativeListView::Horizontal && !d->isRightToLeft() && event->key() == Qt::Key_Right) || (d->orient == QDeclarativeListView::Horizontal && d->isRightToLeft() && event->key() == Qt::Key_Left) || (d->orient == QDeclarativeListView::Vertical && event->key() == Qt::Key_Down)) { if (currentIndex() < d->model->count() - 1 || (d->wrap && !event->isAutoRepeat())) { -- cgit v0.12 From cd19ab9f306f777b495cceabaf57a6eeaf86a82a Mon Sep 17 00:00:00 2001 From: Sami Merila Date: Tue, 12 Apr 2011 09:32:06 +0300 Subject: Two QListView autotests do not pass on Symbian^3 releases tst_QListView::taskQTBUG_2678_spacingAndWrappedText() fails because: QS60Style adds to the itemview item content size margins and empty space, which shouldn't be part of the content size. As a fix, remove these. taskQTBUG_435_deselectOnViewportClick() fails because: Sending a click to a selected itemview item, when it should be sent to below that specific one. It was using hardcoded (center + 20) and autotest assumed that this would be outside of first item. In S60 with touch support, the itemview items are rather tall (49 pixels). As a fix, autotest now uses calculated value, which ensures that click is sent to outside first item. Task-number: QT-4810 Reviewed-by: Tomi Vihria --- src/gui/styles/qs60style.cpp | 2 -- tests/auto/qlistview/tst_qlistview.cpp | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/gui/styles/qs60style.cpp b/src/gui/styles/qs60style.cpp index 585986d..91ac45e 100644 --- a/src/gui/styles/qs60style.cpp +++ b/src/gui/styles/qs60style.cpp @@ -2664,8 +2664,6 @@ QSize QS60Style::sizeFromContents(ContentsType ct, const QStyleOption *opt, } } sz = QCommonStyle::sizeFromContents( ct, opt, csz, widget); - //native items have small empty areas at the beginning and end of menu item - sz.setWidth(sz.width() + 2 * pixelMetric(PM_MenuHMargin) + 2 * QS60StylePrivate::pixelMetric(PM_FrameCornerWidth)); if (QS60StylePrivate::isTouchSupported()) { //Make itemview easier to use in touch devices sz.setHeight(sz.height() + 2 * pixelMetric(PM_FocusFrameVMargin)); diff --git a/tests/auto/qlistview/tst_qlistview.cpp b/tests/auto/qlistview/tst_qlistview.cpp index b6e69a0..ee03386 100644 --- a/tests/auto/qlistview/tst_qlistview.cpp +++ b/tests/auto/qlistview/tst_qlistview.cpp @@ -1893,7 +1893,8 @@ void tst_QListView::taskQTBUG_435_deselectOnViewportClick() QCOMPARE(view.selectionModel()->selectedIndexes().count(), model.rowCount()); - QPoint p = view.visualRect(model.index(model.rowCount() - 1)).center() + QPoint(0, 20); + const QRect itemRect = view.visualRect(model.index(model.rowCount() - 1)); + QPoint p = view.visualRect(model.index(model.rowCount() - 1)).center() + QPoint(0, itemRect.height()); //first the left button QTest::mouseClick(view.viewport(), Qt::LeftButton, 0, p); QVERIFY(!view.selectionModel()->hasSelection()); -- cgit v0.12 From 80083187af81316d436483e5fc39cfddccc821cc Mon Sep 17 00:00:00 2001 From: Guoqing Zhang Date: Tue, 12 Apr 2011 10:59:43 +0300 Subject: Add focus frame support in style sheet Task-number: QTBUG-16207 Reviewed-by: Sami Merila --- src/gui/styles/qstylesheetstyle.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/gui/styles/qstylesheetstyle.cpp b/src/gui/styles/qstylesheetstyle.cpp index 6a0bf5e..369a0f0 100644 --- a/src/gui/styles/qstylesheetstyle.cpp +++ b/src/gui/styles/qstylesheetstyle.cpp @@ -3340,9 +3340,11 @@ void QStyleSheetStyle::drawControl(ControlElement ce, const QStyleOption *opt, Q break; case CE_FocusFrame: - if (rule.hasBorder()) + if (!rule.hasNativeBorder()) { rule.drawBorder(p, opt->rect); - return; + return; + } + break; case CE_PushButton: if (const QStyleOptionButton *btn = qstyleoption_cast(opt)) { -- cgit v0.12 From 7e032238ef7a91f4a9c1337b5e06204fadbc6f55 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 12 Apr 2011 11:04:41 +0200 Subject: Revert "Have the backing store destroyed also in special Symbian scenarios." This reverts commit a12d41076919a133e63de63dff5c1a131a0564e4. --- src/gui/kernel/qwidget.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp index be615a4..0a73481 100644 --- a/src/gui/kernel/qwidget.cpp +++ b/src/gui/kernel/qwidget.cpp @@ -234,8 +234,7 @@ void QWidgetBackingStoreTracker::registerWidget(QWidget *w) */ void QWidgetBackingStoreTracker::unregisterWidget(QWidget *w) { - m_widgets.remove(w); - if (m_widgets.isEmpty()) { + if (m_widgets.remove(w) && m_widgets.isEmpty()) { delete m_ptr; m_ptr = 0; } -- cgit v0.12 From 8b9c94c95ef5dd9620dc35c4ab20cd109369636f Mon Sep 17 00:00:00 2001 From: Sami Merila Date: Tue, 12 Apr 2011 12:13:21 +0300 Subject: QS60Style: itemview item with checkbox and text is drawn incorrectly QS60Style deduces incorrectly when itemview only contains checkbox. This is minor, yet highly annoying bug that prevents highlighted itemview item from showing its content with themes that have opaque itemview item highlight (highlight covers the text that is underneath). As a fix, check itemview item text and icon content before declaring it as "checkbox only". Task-number: QTBUG-18694 Reviewed-by: Tomi Vihria --- src/gui/styles/qs60style.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/styles/qs60style.cpp b/src/gui/styles/qs60style.cpp index 91ac45e..f146075 100644 --- a/src/gui/styles/qs60style.cpp +++ b/src/gui/styles/qs60style.cpp @@ -3132,7 +3132,7 @@ QRect QS60Style::subElementRect(SubElement element, const QStyleOption *opt, con } break; case SE_ItemViewItemCheckIndicator: - if (const QStyleOptionViewItemV2 *vopt = qstyleoption_cast(opt)) { + if (const QStyleOptionViewItemV4 *vopt = qstyleoption_cast(opt)) { const QAbstractItemView *listItem = qobject_cast(widget); const bool singleSelection = listItem && @@ -3140,7 +3140,7 @@ QRect QS60Style::subElementRect(SubElement element, const QStyleOption *opt, con listItem->selectionMode() == QAbstractItemView::NoSelection); const bool checkBoxOnly = (vopt->features & QStyleOptionViewItemV2::HasCheckIndicator) && listItem && - singleSelection; + singleSelection && vopt->text.isEmpty() && vopt->icon.isNull(); // Selection check mark rect. const int indicatorWidth = QS60StylePrivate::pixelMetric(PM_IndicatorWidth); -- cgit v0.12 From 7f8773a209567fb9c962602b8b1f4ec70e38ea51 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 22 Mar 2011 20:08:22 +0100 Subject: prefix TEMPLATE_PREFIX to TEMPLATE even if it is "default-constructed" that way prf files don't have to check both the prefix and the actual template to identify visual studio mode. Reviewed-by: mariusSO --- qmake/project.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/qmake/project.cpp b/qmake/project.cpp index e985401..16200f1 100644 --- a/qmake/project.cpp +++ b/qmake/project.cpp @@ -3028,17 +3028,17 @@ QStringList &QMakeProject::values(const QString &_var, QMap Date: Tue, 22 Mar 2011 20:20:18 +0100 Subject: clean up visual studio identification code TEMPLATE is (now) reliably prefixed with "vc" when a vs generator is used. Reviewed-by: mariusSO --- mkspecs/features/incredibuild_xge.prf | 2 +- mkspecs/features/moc.prf | 8 ++++---- mkspecs/features/win32/embed_manifest_dll.prf | 2 +- mkspecs/features/win32/embed_manifest_exe.prf | 2 +- mkspecs/features/win32/qaxserver.prf | 10 ++-------- mkspecs/wince50standard-armv4i-msvc2005/default_post.prf | 2 +- mkspecs/wince50standard-mipsii-msvc2005/default_post.prf | 2 +- mkspecs/wince50standard-x86-msvc2005/default_post.prf | 2 +- mkspecs/wincewm50pocket-msvc2005/default_post.prf | 2 +- mkspecs/wincewm50smart-msvc2005/default_post.prf | 2 +- mkspecs/wincewm60professional-msvc2005/default_post.prf | 2 +- mkspecs/wincewm60standard-msvc2005/default_post.prf | 2 +- 12 files changed, 16 insertions(+), 22 deletions(-) diff --git a/mkspecs/features/incredibuild_xge.prf b/mkspecs/features/incredibuild_xge.prf index a81a0cc..97ccc44 100644 --- a/mkspecs/features/incredibuild_xge.prf +++ b/mkspecs/features/incredibuild_xge.prf @@ -1,4 +1,4 @@ -contains(TEMPLATE, "vc.*")|contains(TEMPLATE_PREFIX, "vc") { +contains(TEMPLATE, "vc.*") { EOC = $$escape_expand(\\n\\t) # The VCPROJ generator will replace the \r\h with the coded \r\n: diff --git a/mkspecs/features/moc.prf b/mkspecs/features/moc.prf index 89e9b40..d0b36e4 100644 --- a/mkspecs/features/moc.prf +++ b/mkspecs/features/moc.prf @@ -16,7 +16,7 @@ win32:count($$list($$INCLUDEPATH), 40, >) { EOC = $$escape_expand(\\n\\t) - if(contains(TEMPLATE, "vc.*")|contains(TEMPLATE_PREFIX, "vc")) { + contains(TEMPLATE, "vc.*") { # the VCPROJ generator will replace the \r\h with the coded \r\n: # No other generator understands the \h if(win32-msvc2*|wince*msvc*): EOC = $$escape_expand(\\r\\h) @@ -42,7 +42,7 @@ win32:count($$list($$INCLUDEPATH), 40, >) { defineReplace(mocCmdBase) { !isEmpty(WIN_INCLUDETEMP) { RET = - if(contains(TEMPLATE, "vc.*")|contains(TEMPLATE_PREFIX, "vc")) { + contains(TEMPLATE, "vc.*") { RET += $$mocinclude.commands } RET += $$QMAKE_MOC $(DEFINES) @$$WIN_INCLUDETEMP $$join(QMAKE_COMPILER_DEFINES, " -D", -D) @@ -59,7 +59,7 @@ moc_header.output = $$MOC_DIR/$${QMAKE_H_MOD_MOC}${QMAKE_FILE_BASE}$${first(QMAK moc_header.input = HEADERS moc_header.variable_out = SOURCES moc_header.name = MOC ${QMAKE_FILE_IN} -if(!contains(TEMPLATE, "vc.*"):!contains(TEMPLATE_PREFIX, "vc")) { +!contains(TEMPLATE, "vc.*") { !isEmpty(INCLUDETEMP):moc_header.depends += $$INCLUDETEMP } silent:moc_header.commands = @echo moc ${QMAKE_FILE_IN} && $$moc_header.commands @@ -73,7 +73,7 @@ moc_source.commands = ${QMAKE_FUNC_mocCmdBase} ${QMAKE_FILE_IN} -o ${QMAKE_FILE_ moc_source.output = $$MOC_DIR/$${QMAKE_CPP_MOD_MOC}${QMAKE_FILE_BASE}$${QMAKE_EXT_CPP_MOC} moc_source.input = SOURCES OBJECTIVE_SOURCES moc_source.name = MOC ${QMAKE_FILE_IN} -if(!contains(TEMPLATE, "vc.*"):!contains(TEMPLATE_PREFIX, "vc")) { +!contains(TEMPLATE, "vc.*") { !isEmpty(INCLUDETEMP):moc_source.depends += $$INCLUDETEMP } silent:moc_source.commands = @echo moc ${QMAKE_FILE_IN} && $$moc_source.commands diff --git a/mkspecs/features/win32/embed_manifest_dll.prf b/mkspecs/features/win32/embed_manifest_dll.prf index 69c9d1d..5545a62 100644 --- a/mkspecs/features/win32/embed_manifest_dll.prf +++ b/mkspecs/features/win32/embed_manifest_dll.prf @@ -1,4 +1,4 @@ -!if(plugin:no_plugin_manifest):if(win32-msvc2005*|win32-msvc2008*|win32-msvc2010*):!static:!equals(TEMPLATE_PREFIX, "vc"):equals(TEMPLATE, "lib") { +!if(plugin:no_plugin_manifest):if(win32-msvc2005*|win32-msvc2008*|win32-msvc2010*):!static:equals(TEMPLATE, "lib") { MANIFEST_DIR = $$OBJECTS_DIR isEmpty(MANIFEST_DIR):MANIFEST_DIR = . NOPATH_TARGET = $$TARGET diff --git a/mkspecs/features/win32/embed_manifest_exe.prf b/mkspecs/features/win32/embed_manifest_exe.prf index 44aadfa..c6d012e 100644 --- a/mkspecs/features/win32/embed_manifest_exe.prf +++ b/mkspecs/features/win32/embed_manifest_exe.prf @@ -1,4 +1,4 @@ -if(win32-msvc2005*|win32-msvc2008*|win32-msvc2010*):!equals(TEMPLATE_PREFIX, "vc"):equals(TEMPLATE, "app") { +if(win32-msvc2005*|win32-msvc2008*|win32-msvc2010*):equals(TEMPLATE, "app") { MANIFEST_DIR = $$OBJECTS_DIR isEmpty(MANIFEST_DIR):MANIFEST_DIR = . NOPATH_TARGET = $$TARGET diff --git a/mkspecs/features/win32/qaxserver.prf b/mkspecs/features/win32/qaxserver.prf index 2899976..a6c0869 100644 --- a/mkspecs/features/win32/qaxserver.prf +++ b/mkspecs/features/win32/qaxserver.prf @@ -8,12 +8,7 @@ isEmpty(ACTIVEQT_VERSION):ACTIVEQT_VERSION = 1.0 DEFINES += QAXSERVER -ACTIVEQT_IDE = makefile -equals(TEMPLATE_PREFIX, "vc"):ACTIVEQT_IDE = VisualStudio -equals(TEMPLATE, "vcapp"):ACTIVEQT_IDE = VisualStudio -equals(TEMPLATE, "vclib"):ACTIVEQT_IDE = VisualStudio - -equals(ACTIVEQT_IDE, "VisualStudio") { +contains(TEMPLATE, "vc.*") { ACTIVEQT_IDC = $${QMAKE_IDC} ### Qt5: remove me qtPrepareTool(ACTIVEQT_IDC, idc) ACTIVEQT_IDL = $${QMAKE_IDL} @@ -27,8 +22,7 @@ equals(ACTIVEQT_IDE, "VisualStudio") { } ACTIVEQT_TLBOUT = "$(TargetDir)/$${TARGET}.tlb" GENERATED += $${OBJECTS_DIR}/$${TARGET}.idl $${ACTIVEQT_TLBOUT} -} -equals(ACTIVEQT_IDE, "makefile") { +} else { ACTIVEQT_IDC = -$(IDC) ACTIVEQT_IDL = -$(IDL) ACTIVEQT_NEWLINE = $$escape_expand(\\n\\t) diff --git a/mkspecs/wince50standard-armv4i-msvc2005/default_post.prf b/mkspecs/wince50standard-armv4i-msvc2005/default_post.prf index 3dab72a..900d758 100644 --- a/mkspecs/wince50standard-armv4i-msvc2005/default_post.prf +++ b/mkspecs/wince50standard-armv4i-msvc2005/default_post.prf @@ -1,6 +1,6 @@ # Visual Studio has some definitions set internally. # Thus we do not need to redefine these. -if(equals(TEMPLATE_PREFIX, "vc") | equals(TEMPLATE, "vc*")) { +equals(TEMPLATE, "vc.*") { DEFINES -= _M_ARM QMAKE_CXXFLAGS += -fp:precise } diff --git a/mkspecs/wince50standard-mipsii-msvc2005/default_post.prf b/mkspecs/wince50standard-mipsii-msvc2005/default_post.prf index d3e49ab..4dbcf35 100644 --- a/mkspecs/wince50standard-mipsii-msvc2005/default_post.prf +++ b/mkspecs/wince50standard-mipsii-msvc2005/default_post.prf @@ -1,6 +1,6 @@ # Visual Studio has some definitions set internally. # Thus we do not need to redefine these. -if(equals(TEMPLATE_PREFIX, "vc") | equals(TEMPLATE, "vc*")) { +contains(TEMPLATE, "vc.*") { DEFINES -= _M_MRX000=3000 QMAKE_CXXFLAGS += -fp:precise } diff --git a/mkspecs/wince50standard-x86-msvc2005/default_post.prf b/mkspecs/wince50standard-x86-msvc2005/default_post.prf index 6790c60..2436efb 100644 --- a/mkspecs/wince50standard-x86-msvc2005/default_post.prf +++ b/mkspecs/wince50standard-x86-msvc2005/default_post.prf @@ -1,6 +1,6 @@ # Visual Studio has some definitions set internally. # Thus we do not need to redefine these. -if(equals(TEMPLATE_PREFIX, "vc") | equals(TEMPLATE, "vc*")) { +equals(TEMPLATE, "vc.*") { QMAKE_CXXFLAGS += -fp:precise } diff --git a/mkspecs/wincewm50pocket-msvc2005/default_post.prf b/mkspecs/wincewm50pocket-msvc2005/default_post.prf index 3dab72a..84ea15e 100644 --- a/mkspecs/wincewm50pocket-msvc2005/default_post.prf +++ b/mkspecs/wincewm50pocket-msvc2005/default_post.prf @@ -1,6 +1,6 @@ # Visual Studio has some definitions set internally. # Thus we do not need to redefine these. -if(equals(TEMPLATE_PREFIX, "vc") | equals(TEMPLATE, "vc*")) { +contains(TEMPLATE, "vc.*") { DEFINES -= _M_ARM QMAKE_CXXFLAGS += -fp:precise } diff --git a/mkspecs/wincewm50smart-msvc2005/default_post.prf b/mkspecs/wincewm50smart-msvc2005/default_post.prf index 3dab72a..84ea15e 100644 --- a/mkspecs/wincewm50smart-msvc2005/default_post.prf +++ b/mkspecs/wincewm50smart-msvc2005/default_post.prf @@ -1,6 +1,6 @@ # Visual Studio has some definitions set internally. # Thus we do not need to redefine these. -if(equals(TEMPLATE_PREFIX, "vc") | equals(TEMPLATE, "vc*")) { +contains(TEMPLATE, "vc.*") { DEFINES -= _M_ARM QMAKE_CXXFLAGS += -fp:precise } diff --git a/mkspecs/wincewm60professional-msvc2005/default_post.prf b/mkspecs/wincewm60professional-msvc2005/default_post.prf index 3dab72a..84ea15e 100644 --- a/mkspecs/wincewm60professional-msvc2005/default_post.prf +++ b/mkspecs/wincewm60professional-msvc2005/default_post.prf @@ -1,6 +1,6 @@ # Visual Studio has some definitions set internally. # Thus we do not need to redefine these. -if(equals(TEMPLATE_PREFIX, "vc") | equals(TEMPLATE, "vc*")) { +contains(TEMPLATE, "vc.*") { DEFINES -= _M_ARM QMAKE_CXXFLAGS += -fp:precise } diff --git a/mkspecs/wincewm60standard-msvc2005/default_post.prf b/mkspecs/wincewm60standard-msvc2005/default_post.prf index 3dab72a..84ea15e 100644 --- a/mkspecs/wincewm60standard-msvc2005/default_post.prf +++ b/mkspecs/wincewm60standard-msvc2005/default_post.prf @@ -1,6 +1,6 @@ # Visual Studio has some definitions set internally. # Thus we do not need to redefine these. -if(equals(TEMPLATE_PREFIX, "vc") | equals(TEMPLATE, "vc*")) { +contains(TEMPLATE, "vc.*") { DEFINES -= _M_ARM QMAKE_CXXFLAGS += -fp:precise } -- cgit v0.12 From 3838388e8143ac5f5e1f3688f9ba31190fd9bbd3 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 23 Mar 2011 12:31:48 +0100 Subject: useful location reporting for errors from QMAKE_SUBSTITUTES Reviewed-by: mariusSO --- qmake/generators/makefile.cpp | 2 +- qmake/project.cpp | 14 ++++++++++++++ qmake/project.h | 1 + 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index c13f38e..f9eba22 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -545,7 +545,7 @@ MakefileGenerator::init() else state.pop(); } else if(state.isEmpty() || state.top() == IN_CONDITION) { - contents += project->expand(line).join(QString(Option::field_sep)); + contents += project->expand(line, in.fileName(), count); } } if(out.exists() && out.open(QFile::ReadOnly)) { diff --git a/qmake/project.cpp b/qmake/project.cpp index 16200f1..d4f21be 100644 --- a/qmake/project.cpp +++ b/qmake/project.cpp @@ -2773,6 +2773,20 @@ QMakeProject::expand(const QString &str) return QStringList(); } +QString +QMakeProject::expand(const QString &str, const QString &file, int line) +{ + bool ok; + parser_info pi = parser; + parser.file = file; + parser.line_no = line; + parser.from_file = false; + QMap tmp = vars; + const QStringList ret = doVariableReplaceExpand(str, tmp, &ok); + parser = pi; + return ok ? ret.join(QString(Option::field_sep)) : QString(); +} + QStringList QMakeProject::expand(const QString &func, const QList &args) { diff --git a/qmake/project.h b/qmake/project.h index 09aa45e..0e6131d 100644 --- a/qmake/project.h +++ b/qmake/project.h @@ -144,6 +144,7 @@ public: QMap &place); QStringList expand(const QString &v); + QString expand(const QString &v, const QString &file, int line); QStringList expand(const QString &func, const QList &args); bool test(const QString &v); bool test(const QString &func, const QList &args); -- cgit v0.12 From ec834adf0ce004cb2919766dc12b31963d320f56 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 23 Mar 2011 12:57:49 +0100 Subject: make uic3-generated moc files depend on mocinclude.tmp Task-number: QTBUG-16951 Reviewed-by: mariusSO --- mkspecs/features/uic.prf | 1 + 1 file changed, 1 insertion(+) diff --git a/mkspecs/features/uic.prf b/mkspecs/features/uic.prf index 0a18b47..74a2683 100644 --- a/mkspecs/features/uic.prf +++ b/mkspecs/features/uic.prf @@ -77,6 +77,7 @@ uic3 { uic3_moc.input = UIC3_HEADERS uic3_moc.variable_out = GENERATED_SOURCES uic3_moc.name = $$moc_header.name + !contains(TEMPLATE, "vc.*"):!isEmpty(INCLUDETEMP):uic3_moc.depends += $$INCLUDETEMP QMAKE_EXTRA_COMPILERS += uic3_moc } -- cgit v0.12 From 3aa39b0164ce4bb9e551feb0417990e5679c5209 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 23 Mar 2011 17:07:36 +0100 Subject: create a pwd string with a trailing slash only on demand Reviewed-by: mariusSO --- qmake/generators/makefile.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index f9eba22..f5b7295 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -2825,9 +2825,6 @@ MakefileGenerator::fileFixify(const QString& file, const QString &out_d, const Q return cacheVal; //do the fixin' - QString pwd = qmake_getpwd(); - if (!pwd.endsWith('/')) - pwd += '/'; QString orig_file = ret; if(ret.startsWith(QLatin1Char('~'))) { if(ret.startsWith(QLatin1String("~/"))) @@ -2836,12 +2833,16 @@ MakefileGenerator::fileFixify(const QString& file, const QString &out_d, const Q warn_msg(WarnLogic, "Unable to expand ~ in %s", ret.toLatin1().constData()); } if(fix == FileFixifyAbsolute || (fix == FileFixifyDefault && project->isActiveConfig("no_fixpath"))) { - if(fix == FileFixifyAbsolute && QDir::isRelativePath(ret)) //already absolute + if(fix == FileFixifyAbsolute && QDir::isRelativePath(ret)) { //already absolute + QString pwd = qmake_getpwd(); + if (!pwd.endsWith(QLatin1Char('/'))) + pwd += QLatin1Char('/'); ret.prepend(pwd); + } ret = Option::fixPathToTargetOS(ret, false, canon); } else { //fix it.. QString out_dir = QDir(Option::output_dir).absoluteFilePath(out_d); - QString in_dir = QDir(pwd).absoluteFilePath(in_d); + QString in_dir = QDir(qmake_getpwd()).absoluteFilePath(in_d); { QFileInfo in_fi(fileInfo(in_dir)); if(in_fi.exists()) @@ -2907,7 +2908,7 @@ MakefileGenerator::fileFixify(const QString& file, const QString &out_d, const Q ret = "."; debug_msg(3, "Fixed[%d,%d] %s :: to :: %s [%s::%s] [%s::%s]", fix, canon, orig_file.toLatin1().constData(), ret.toLatin1().constData(), in_d.toLatin1().constData(), out_d.toLatin1().constData(), - pwd.toLatin1().constData(), Option::output_dir.toLatin1().constData()); + qmake_getpwd().toLatin1().constData(), Option::output_dir.toLatin1().constData()); cache->insert(cacheKey, ret); return ret; } -- cgit v0.12 From 11604357fccb59f7aba8165ea7ca8846eb820858 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Thu, 24 Mar 2011 12:58:15 +0100 Subject: stop fixifying after first success somewhat unlikely that this had much real-world effects ... except eating yet more cpu. Reviewed-by: mariusSO --- qmake/generators/makefile.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index f5b7295..9c22ca4 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -2896,6 +2896,7 @@ MakefileGenerator::fileFixify(const QString& file, const QString &out_d, const Q //prepend for(int o = 0; o < i; o++) dot_prefix += ".." + Option::dir_sep; + break; } } ret.prepend(dot_prefix); -- cgit v0.12 From af93be4d81d1e50b0c9f015f8432033cc737b22d Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 29 Mar 2011 10:22:10 +0200 Subject: simplify: the input and output dirs are already normalized Reviewed-by: mariusSO --- qmake/generators/makefile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index 9c22ca4..7033a04 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -782,7 +782,7 @@ MakefileGenerator::init() } { //get the output_dir into the pwd - if(fileFixify(Option::output_dir) != fileFixify(qmake_getpwd())) + if(Option::output_dir != qmake_getpwd()) project->values("INCLUDEPATH").append(fileFixify(Option::output_dir, Option::output_dir, Option::output_dir)); -- cgit v0.12 From 2fe0805d4eb821d2aa11ea868ebb3ff32a108475 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 29 Mar 2011 10:24:15 +0200 Subject: simplify: fileFixify for all same paths is always "." this must have been the most arcane way to generate a single dot ever Reviewed-by: mariusSO --- qmake/generators/makefile.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index 7033a04..1bfbdba 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -783,9 +783,7 @@ MakefileGenerator::init() { //get the output_dir into the pwd if(Option::output_dir != qmake_getpwd()) - project->values("INCLUDEPATH").append(fileFixify(Option::output_dir, - Option::output_dir, - Option::output_dir)); + project->values("INCLUDEPATH").append("."); } //fix up the target deps -- cgit v0.12 From c74f29f28f2bfee8335820a67598d16e850e9444 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 29 Mar 2011 10:28:27 +0200 Subject: simplify: absolute fixification ignores the base dir arguments Reviewed-by: mariusSO --- qmake/generators/makefile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index 1bfbdba..8159804 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -2460,7 +2460,7 @@ MakefileGenerator::writeSubTargets(QTextStream &t, QListprofile.isEmpty()) { QString out = subtarget->makefile; - QString in = fileFixify(in_directory + subtarget->profile, out_directory, QString(), FileFixifyAbsolute); + QString in = fileFixify(in_directory + subtarget->profile, FileFixifyAbsolute); if(out.startsWith(in_directory)) out = out.mid(in_directory.length()); t << mkfile << ": " << "\n\t"; -- cgit v0.12 From 9df9d83085ff6164d83c35d51df539858ae398e4 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 29 Mar 2011 10:28:51 +0200 Subject: fix paths of vpath-resolved files Task-number: QTBUG-8169 Reviewed-by: mariusSO --- qmake/generators/makefile.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index 8159804..7eccc2e 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -364,7 +364,7 @@ MakefileGenerator::findFilesInVPATH(QStringList l, uchar flags, const QString &v dir = regex.left(regex.lastIndexOf(Option::dir_sep) + 1); real_dir = dir; if(!(flags & VPATH_NoFixify)) - real_dir = fileFixify(real_dir, qmake_getpwd(), Option::output_dir); + real_dir = fileFixify(real_dir, qmake_getpwd(), Option::output_dir) + '/'; regex.remove(0, dir.length()); } if(real_dir.isEmpty() || exists(real_dir)) { @@ -383,16 +383,15 @@ MakefileGenerator::findFilesInVPATH(QStringList l, uchar flags, const QString &v for(int i = (int)files.count()-1; i >= 0; i--) { if(files[i] == "." || files[i] == "..") continue; - a = dir + files[i]; + a = real_dir + files[i]; if(!(flags & VPATH_NoFixify)) a = fileFixify(a); l.insert(val_it, a); } } } else { - debug_msg(1, "%s:%d Cannot match %s%c%s, as %s does not exist.", + debug_msg(1, "%s:%d Cannot match %s%s, as %s does not exist.", __FILE__, __LINE__, real_dir.toLatin1().constData(), - QDir::separator().toLatin1(), regex.toLatin1().constData(), real_dir.toLatin1().constData()); if(flags & VPATH_RemoveMissingFiles) remove_file = true; -- cgit v0.12 From 430b743946178c3f05208434331b8017159612b1 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 29 Mar 2011 10:33:45 +0200 Subject: dist target: fixify OBJECTS_DIR against output dir the thing is terminally broken anyway, but whatever Reviewed-by: mariusSO --- qmake/generators/unix/unixmake2.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/qmake/generators/unix/unixmake2.cpp b/qmake/generators/unix/unixmake2.cpp index c660855..c0c0aaa 100644 --- a/qmake/generators/unix/unixmake2.cpp +++ b/qmake/generators/unix/unixmake2.cpp @@ -787,7 +787,8 @@ UnixMakefileGenerator::writeMakeParts(QTextStream &t) ddir = project->first("QMAKE_DISTDIR"); QString ddir_c = escapeFilePath(fileFixify((project->isEmpty("OBJECTS_DIR") ? QString(".tmp/") : - project->first("OBJECTS_DIR")) + ddir)); + project->first("OBJECTS_DIR")) + ddir, + Option::output_dir, Option::output_dir)); t << "dist: " << "\n\t" << mkdir_p_asstring(ddir_c) << "\n\t" << "$(COPY_FILE) --parents $(SOURCES) $(DIST) " << ddir_c << Option::dir_sep << " && "; -- cgit v0.12 From 26dd9a45c3b1e92c356ee7f80f728e2ddca0c1d8 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 29 Mar 2011 13:56:23 +0200 Subject: fix fixifying of QMAKE_SUBSTITUTES use the correct bases. notably, don't expect the input file in the output dir. Reviewed-by: mariusSO --- qmake/generators/makefile.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index 7eccc2e..d096eb4 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -483,19 +483,22 @@ MakefileGenerator::init() subs.at(i).toLatin1().constData()); continue; } - inn = tinn.first(); - outn = toutn.first(); + inn = fileFixify(tinn.first(), qmake_getpwd()); + outn = fileFixify(toutn.first(), qmake_getpwd(), Option::output_dir); } else { - inn = subs.at(i); + inn = fileFixify(subs.at(i), qmake_getpwd()); + if (!QFile::exists(inn)) { + // random insanity for backwards compat: .in file specified with absolute out dir + inn = fileFixify(subs.at(i)); + } if(!inn.endsWith(".in")) { warn_msg(WarnLogic, "Substitute '%s' does not end with '.in'", inn.toLatin1().constData()); continue; } - outn = inn.left(inn.length()-3); + outn = fileFixify(inn.left(inn.length()-3), qmake_getpwd(), Option::output_dir); } - QFile in(fileFixify(inn)); - QFile out(fileFixify(outn, qmake_getpwd(), Option::output_dir)); + QFile in(inn); if(in.open(QFile::ReadOnly)) { QString contents; QStack state; @@ -547,6 +550,7 @@ MakefileGenerator::init() contents += project->expand(line, in.fileName(), count); } } + QFile out(outn); if(out.exists() && out.open(QFile::ReadOnly)) { QString old = QString::fromUtf8(out.readAll()); if(contents == old) { -- cgit v0.12 From 8b11ebf392d832725185de08c2438d6b8771890b Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 29 Mar 2011 14:42:35 +0200 Subject: fixify target source against build tree that's where one would expect a target, after all. affects only extra targets explicitly requesting fixification, i.e., nothing. Reviewed-by: mariusSO --- qmake/generators/makefile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index d096eb4..3c5948f 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -1747,7 +1747,7 @@ MakefileGenerator::writeExtraTargets(QTextStream &t) deps += " " + escapeDependencyPath(dep); } if(project->values((*it) + ".CONFIG").indexOf("fix_target") != -1) - targ = fileFixify(targ); + targ = fileFixify(targ, Option::output_dir, Option::output_dir); if(project->isEmpty("QMAKE_NOFORCE") && project->values((*it) + ".CONFIG").indexOf("phony") != -1) deps += QString(" ") + "FORCE"; -- cgit v0.12 From a5be47714e5a0075fe9d0ea4a7925136a48e3974 Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 29 Mar 2011 11:54:38 +0200 Subject: run depend_command in build dir in VS generators as well followup to b139e7e96e5c47b412c4f0bbc4ae11d5cca99e61 Reviewed-by: mariusSO --- qmake/generators/win32/msbuild_objectmodel.cpp | 5 ++++- qmake/generators/win32/msvc_objectmodel.cpp | 5 ++++- qmake/generators/win32/msvc_vcproj.cpp | 6 +++++- qmake/generators/win32/msvc_vcxproj.cpp | 6 +++++- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/qmake/generators/win32/msbuild_objectmodel.cpp b/qmake/generators/win32/msbuild_objectmodel.cpp index bd94178..01f730a 100644 --- a/qmake/generators/win32/msbuild_objectmodel.cpp +++ b/qmake/generators/win32/msbuild_objectmodel.cpp @@ -2438,6 +2438,9 @@ bool VCXFilter::addExtraCompiler(const VCXFilterFile &info) char buff[256]; QString dep_cmd = Project->replaceExtraCompilerVariables(tmp_dep_cmd, Option::fixPathToLocalOS(inFile, true, false), out); if(Project->canExecute(dep_cmd)) { + dep_cmd.prepend(QLatin1String("cd ") + + Project->escapeFilePath(Option::fixPathToLocalOS(Option::output_dir, false)) + + QLatin1String(" && ")); if(FILE *proc = QT_POPEN(dep_cmd.toLatin1().constData(), "r")) { QString indeps; while(!feof(proc)) { @@ -2452,7 +2455,7 @@ bool VCXFilter::addExtraCompiler(const VCXFilterFile &info) for (int i = 0; i < extradeps.count(); ++i) { QString dd = extradeps.at(i).simplified(); if (!dd.isEmpty()) - deps += Project->fileFixify(dd); + deps += Project->fileFixify(dd, QString(), Option::output_dir); } } } diff --git a/qmake/generators/win32/msvc_objectmodel.cpp b/qmake/generators/win32/msvc_objectmodel.cpp index 87c8943..0a24a01 100644 --- a/qmake/generators/win32/msvc_objectmodel.cpp +++ b/qmake/generators/win32/msvc_objectmodel.cpp @@ -2218,6 +2218,9 @@ bool VCFilter::addExtraCompiler(const VCFilterFile &info) Option::fixPathToLocalOS(inFile, true, false), out); if(Project->canExecute(dep_cmd)) { + dep_cmd.prepend(QLatin1String("cd ") + + Project->escapeFilePath(Option::fixPathToLocalOS(Option::output_dir, false)) + + QLatin1String(" && ")); if(FILE *proc = QT_POPEN(dep_cmd.toLatin1().constData(), "r")) { QString indeps; while(!feof(proc)) { @@ -2232,7 +2235,7 @@ bool VCFilter::addExtraCompiler(const VCFilterFile &info) for (int i = 0; i < extradeps.count(); ++i) { QString dd = extradeps.at(i).simplified(); if (!dd.isEmpty()) - deps += Project->fileFixify(dd); + deps += Project->fileFixify(dd, QString(), Option::output_dir); } } } diff --git a/qmake/generators/win32/msvc_vcproj.cpp b/qmake/generators/win32/msvc_vcproj.cpp index 364eca0..10934a5 100644 --- a/qmake/generators/win32/msvc_vcproj.cpp +++ b/qmake/generators/win32/msvc_vcproj.cpp @@ -1302,6 +1302,9 @@ void VcprojGenerator::initResourceFiles() dep_cmd = Option::fixPathToLocalOS(dep_cmd, true, false); if(canExecute(dep_cmd)) { + dep_cmd.prepend(QLatin1String("cd ") + + escapeFilePath(Option::fixPathToLocalOS(Option::output_dir, false)) + + QLatin1String(" && ")); if(FILE *proc = QT_POPEN(dep_cmd.toLatin1().constData(), "r")) { QString indeps; while(!feof(proc)) { @@ -1312,7 +1315,8 @@ void VcprojGenerator::initResourceFiles() } QT_PCLOSE(proc); if(!indeps.isEmpty()) - deps += fileFixify(indeps.replace('\n', ' ').simplified().split(' ')); + deps += fileFixify(indeps.replace('\n', ' ').simplified().split(' '), + QString(), Option::output_dir); } } } diff --git a/qmake/generators/win32/msvc_vcxproj.cpp b/qmake/generators/win32/msvc_vcxproj.cpp index 2b628a5..e2464ec 100644 --- a/qmake/generators/win32/msvc_vcxproj.cpp +++ b/qmake/generators/win32/msvc_vcxproj.cpp @@ -654,6 +654,9 @@ void VcxprojGenerator::initResourceFiles() dep_cmd = Option::fixPathToLocalOS(dep_cmd, true, false); if(canExecute(dep_cmd)) { + dep_cmd.prepend(QLatin1String("cd ") + + escapeFilePath(Option::fixPathToLocalOS(Option::output_dir, false)) + + QLatin1String(" && ")); if(FILE *proc = QT_POPEN(dep_cmd.toLatin1().constData(), "r")) { QString indeps; while(!feof(proc)) { @@ -664,7 +667,8 @@ void VcxprojGenerator::initResourceFiles() } QT_PCLOSE(proc); if(!indeps.isEmpty()) - deps += fileFixify(indeps.replace('\n', ' ').simplified().split(' ')); + deps += fileFixify(indeps.replace('\n', ' ').simplified().split(' '), + QString(), Option::output_dir); } } } -- cgit v0.12 From 8caba032245dfa310a77c22c1e55137c54e59f4f Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 29 Mar 2011 17:10:35 +0200 Subject: make collection of SUBDIRS in solution generator less bizarre de-duplicate code, and on the way don't try to re-resolve project variables of subprojects against the contents of the top level project. Reviewed-by: mariusSO --- qmake/generators/win32/msvc_vcproj.cpp | 42 +++++++++++++++++----------------- qmake/generators/win32/msvc_vcproj.h | 1 + 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/qmake/generators/win32/msvc_vcproj.cpp b/qmake/generators/win32/msvc_vcproj.cpp index 10934a5..5005190 100644 --- a/qmake/generators/win32/msvc_vcproj.cpp +++ b/qmake/generators/win32/msvc_vcproj.cpp @@ -352,6 +352,25 @@ QUuid VcprojGenerator::increaseUUID(const QUuid &id) return result; } +QStringList VcprojGenerator::collectSubDirs(QMakeProject *proj) +{ + QStringList subdirs; + QStringList tmp_proj_subdirs = proj->variables()["SUBDIRS"]; + for(int x = 0; x < tmp_proj_subdirs.size(); ++x) { + QString tmpdir = tmp_proj_subdirs.at(x); + if(!proj->isEmpty(tmpdir + ".file")) { + if(!proj->isEmpty(tmpdir + ".subdir")) + warn_msg(WarnLogic, "Cannot assign both file and subdir for subdir %s", + tmpdir.toLatin1().constData()); + tmpdir = proj->first(tmpdir + ".file"); + } else if(!proj->isEmpty(tmpdir + ".subdir")) { + tmpdir = proj->first(tmpdir + ".subdir"); + } + subdirs += tmpdir; + } + return subdirs; +} + void VcprojGenerator::writeSubDirs(QTextStream &t) { // Check if all requirements are fulfilled @@ -386,7 +405,6 @@ void VcprojGenerator::writeSubDirs(QTextStream &t) QHash solution_depends; QList solution_cleanup; - QStringList subdirs = project->values("SUBDIRS"); QString oldpwd = qmake_getpwd(); // Make sure that all temp projects are configured @@ -395,16 +413,9 @@ void VcprojGenerator::writeSubDirs(QTextStream &t) QStringList old_after_vars = Option::after_user_vars; Option::after_user_vars.append("CONFIG+=release"); + QStringList subdirs = collectSubDirs(project); for(int i = 0; i < subdirs.size(); ++i) { QString tmp = subdirs.at(i); - if(!project->isEmpty(tmp + ".file")) { - if(!project->isEmpty(tmp + ".subdir")) - warn_msg(WarnLogic, "Cannot assign both file and subdir for subdir %s", - tmp.toLatin1().constData()); - tmp = project->first(tmp + ".file"); - } else if(!project->isEmpty(tmp + ".subdir")) { - tmp = project->first(tmp + ".subdir"); - } QFileInfo fi(fileInfo(Option::fixPathToLocalOS(tmp, true))); if(fi.exists()) { if(fi.isDir()) { @@ -428,19 +439,8 @@ void VcprojGenerator::writeSubDirs(QTextStream &t) continue; } if(tmp_proj.first("TEMPLATE") == "vcsubdirs") { - QStringList tmp_proj_subdirs = tmp_proj.variables()["SUBDIRS"]; - for(int x = 0; x < tmp_proj_subdirs.size(); ++x) { - QString tmpdir = tmp_proj_subdirs.at(x); - if(!tmp_proj.isEmpty(tmpdir + ".file")) { - if(!tmp_proj.isEmpty(tmpdir + ".subdir")) - warn_msg(WarnLogic, "Cannot assign both file and subdir for subdir %s", - tmpdir.toLatin1().constData()); - tmpdir = tmp_proj.first(tmpdir + ".file"); - } else if(!tmp_proj.isEmpty(tmpdir + ".subdir")) { - tmpdir = tmp_proj.first(tmpdir + ".subdir"); - } + foreach(const QString &tmpdir, collectSubDirs(&tmp_proj)) subdirs += fileFixify(tmpdir); - } } else if(tmp_proj.first("TEMPLATE") == "vcapp" || tmp_proj.first("TEMPLATE") == "vclib") { // Initialize a 'fake' project to get the correct variables // and to be able to extract all the dependencies diff --git a/qmake/generators/win32/msvc_vcproj.h b/qmake/generators/win32/msvc_vcproj.h index 8e55211..d66c029 100644 --- a/qmake/generators/win32/msvc_vcproj.h +++ b/qmake/generators/win32/msvc_vcproj.h @@ -130,6 +130,7 @@ protected: QList mergedProjects; private: + QStringList collectSubDirs(QMakeProject *proj); QUuid increaseUUID(const QUuid &id); friend class VCFilter; }; -- cgit v0.12 From e22e36bc61b4af7c0a9113617df5a35ed315dede Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Tue, 29 Mar 2011 20:17:18 +0200 Subject: look for makespec in the build dir first it's more natural to look into the build dir before the source dir, and it's what the qmake-generated makefiles mean when re-invoking qmake. specifically, this works around the problem that relative paths with excess ".."s pointing below the root are happily ignored and thus truly bizarre makespec paths may be constructed by the qmake re-invocations if the source dir is less nested than the build dir. Task-number: QTBUG-9817 Reviewed-by: mariusSO --- qmake/project.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qmake/project.cpp b/qmake/project.cpp index d4f21be..177ab2f 100644 --- a/qmake/project.cpp +++ b/qmake/project.cpp @@ -1345,10 +1345,10 @@ QMakeProject::read(uchar cmd) } if(QDir::isRelativePath(qmakespec)) { - if (QFile::exists(qmakespec+"/qmake.conf")) { - Option::mkfile::qmakespec = QFileInfo(Option::mkfile::qmakespec).absoluteFilePath(); - } else if (QFile::exists(Option::output_dir+"/"+qmakespec+"/qmake.conf")) { + if (QFile::exists(Option::output_dir+"/"+qmakespec+"/qmake.conf")) { qmakespec = Option::mkfile::qmakespec = QFileInfo(Option::output_dir+"/"+qmakespec).absoluteFilePath(); + } else if (QFile::exists(qmakespec+"/qmake.conf")) { + Option::mkfile::qmakespec = QFileInfo(Option::mkfile::qmakespec).absoluteFilePath(); } else { bool found_mkspec = false; for(QStringList::ConstIterator it = mkspec_roots.begin(); it != mkspec_roots.end(); ++it) { -- cgit v0.12 From 565e8679374e71df9f72074dd3c71c929aeeafc8 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 12 Apr 2011 12:35:41 +0200 Subject: Use FixNativeOrientation on Symbian when the application wants it. Applications can request the usage of RWindow::FixNativeOrientation() by setting the new Qt::WA_SymbianNoSystemRotation attribute for their fullscreen top-level widget (which in practice will either be a graphics or declarative view). This will fix the underlying EGL window surface and the QWidget dimensions to the dimension of the native orientation of the device (typically portrait). The default auto-rotation can be left enabled, however it will be up to the application to rotate the drawing. Global notifications, VKB, etc. will still appear in the proper orientation. Another benefit is improved performance in the non-native orientation. Task-number: QTBUG-17742 Reviewed-by: Jason Barron Reviewed-by: Jani Hautakangas --- src/corelib/global/qnamespace.h | 2 + src/corelib/global/qnamespace.qdoc | 1 + src/gui/kernel/qapplication_s60.cpp | 159 ++++++++++++++++++++++++++---------- src/gui/kernel/qt_s60_p.h | 15 ++-- src/gui/kernel/qwidget_s60.cpp | 2 + 5 files changed, 132 insertions(+), 47 deletions(-) diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h index 4d70744..15cc809 100644 --- a/src/corelib/global/qnamespace.h +++ b/src/corelib/global/qnamespace.h @@ -526,6 +526,8 @@ public: WA_X11DoNotAcceptFocus = 132, + WA_SymbianNoSystemRotation = 133, + // Add new attributes before this line WA_AttributeCount }; diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc index 22ad83b..f03fb25 100644 --- a/src/corelib/global/qnamespace.qdoc +++ b/src/corelib/global/qnamespace.qdoc @@ -1244,6 +1244,7 @@ \omitvalue WA_SetWindowModality \omitvalue WA_WState_WindowOpacitySet \omitvalue WA_WState_AcceptedTouchBeginEvent + \omitvalue WA_SymbianNoSystemRotation */ /*! \typedef Qt::HANDLE diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index f80b657..d37845d 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -546,11 +546,52 @@ void QSymbianControl::setWidget(QWidget *w) { qwidget = w; } + +QPoint QSymbianControl::translatePointForFixedNativeOrientation(const TPoint &pointerEventPos) const +{ + QPoint pos(pointerEventPos.iX, pointerEventPos.iY); + if (qwidget->d_func()->fixNativeOrientationCalled) { + QSize wsize = qwidget->size(); + TSize size = Size(); + if (size.iWidth == wsize.height() && size.iHeight == wsize.width()) { + qreal x = pos.x(); + qreal y = pos.y(); + pos.setX(size.iHeight - y); + pos.setY(x); + } + } + return pos; +} + +TRect QSymbianControl::translateRectForFixedNativeOrientation(const TRect &controlRect) const +{ + TRect rect = controlRect; + if (qwidget->d_func()->fixNativeOrientationCalled) { + QPoint a = translatePointForFixedNativeOrientation(rect.iTl); + QPoint b = translatePointForFixedNativeOrientation(rect.iBr); + if (a.x() < b.x()) { + rect.iTl.iX = a.x(); + rect.iBr.iX = b.x(); + } else { + rect.iTl.iX = b.x(); + rect.iBr.iX = a.x(); + } + if (a.y() < b.y()) { + rect.iTl.iY = a.y(); + rect.iBr.iY = b.y(); + } else { + rect.iTl.iY = b.y(); + rect.iBr.iY = a.y(); + } + } + return rect; +} + void QSymbianControl::HandleLongTapEventL( const TPoint& aPenEventLocation, const TPoint& aPenEventScreenLocation ) { QWidget *alienWidget; - QPoint widgetPos = QPoint(aPenEventLocation.iX, aPenEventLocation.iY); - QPoint globalPos = QPoint(aPenEventScreenLocation.iX,aPenEventScreenLocation.iY); + QPoint widgetPos = translatePointForFixedNativeOrientation(aPenEventLocation); + QPoint globalPos = translatePointForFixedNativeOrientation(aPenEventScreenLocation); alienWidget = qwidget->childAt(widgetPos); if (!alienWidget) alienWidget = qwidget; @@ -565,7 +606,7 @@ void QSymbianControl::HandleLongTapEventL( const TPoint& aPenEventLocation, cons void QSymbianControl::translateAdvancedPointerEvent(const TAdvancedPointerEvent *event) { QApplicationPrivate *d = QApplicationPrivate::instance(); - QPointF screenPos = qwidget->mapToGlobal(QPoint(event->iPosition.iX, event->iPosition.iY)); + QPointF screenPos = qwidget->mapToGlobal(translatePointForFixedNativeOrientation(event->iPosition)); qreal pressure; if(d->pressureSupported && event->Pressure() > 0) //workaround for misconfigured HAL @@ -666,7 +707,7 @@ void QSymbianControl::HandlePointerEvent(const TPointerEvent& pEvent) mapS60MouseEventTypeToQt(&type, &button, &pEvent); Qt::KeyboardModifiers modifiers = mapToQtModifiers(pEvent.iModifiers); - QPoint widgetPos = QPoint(pEvent.iPosition.iX, pEvent.iPosition.iY); + QPoint widgetPos = translatePointForFixedNativeOrientation(pEvent.iPosition); TPoint controlScreenPos = PositionRelativeToScreen(); QPoint globalPos = QPoint(controlScreenPos.iX, controlScreenPos.iY) + widgetPos; S60->lastCursorPos = globalPos; @@ -1132,6 +1173,9 @@ void QSymbianControl::Draw(const TRect& controlRect) const Q_ASSERT(window); QTLWExtra *topExtra = window->d_func()->maybeTopData(); Q_ASSERT(topExtra); + + TRect wcontrolRect = translateRectForFixedNativeOrientation(controlRect); + if (!topExtra->inExpose) { topExtra->inExpose = true; if (!qwidget->isWindow()) { @@ -1142,7 +1186,7 @@ void QSymbianControl::Draw(const TRect& controlRect) const gc.SetBrushColor(TRgb(0, 0, 0, 0)); gc.Clear(controlRect); } - QRect exposeRect = qt_TRect2QRect(controlRect); + QRect exposeRect = qt_TRect2QRect(wcontrolRect); qwidget->d_func()->syncBackingStore(exposeRect); topExtra->inExpose = false; } @@ -1155,7 +1199,7 @@ void QSymbianControl::Draw(const TRect& controlRect) const const bool sendNativePaintEvents = qwidget->d_func()->extraData()->receiveNativePaintEvents; if (sendNativePaintEvents) { - const QRect r = qt_TRect2QRect(controlRect); + const QRect r = qt_TRect2QRect(wcontrolRect); QMetaObject::invokeMethod(qwidget, "beginNativePaintEvent", Qt::DirectConnection, Q_ARG(QRect, r)); } @@ -1210,7 +1254,7 @@ void QSymbianControl::Draw(const TRect& controlRect) const } if (sendNativePaintEvents) { - const QRect r = qt_TRect2QRect(controlRect); + const QRect r = qt_TRect2QRect(wcontrolRect); // The draw ops aren't actually sent to WSERV until the graphics // context is deactivated, which happens in the function calling // this one. We therefore delay the delivery of endNativePaintEvent, @@ -1223,14 +1267,45 @@ void QSymbianControl::Draw(const TRect& controlRect) const } } +void QSymbianControl::qwidgetResize_helper(const QSize &newSize) +{ + QRect cr = qwidget->geometry(); + QSize oldSize(cr.size()); + cr.setSize(newSize); + qwidget->data->crect = cr; + if (qwidget->isVisible()) { + QTLWExtra *tlwExtra = qwidget->d_func()->maybeTopData(); + bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt(); + if (!slowResize && tlwExtra) + tlwExtra->inTopLevelResize = true; + QResizeEvent e(newSize, oldSize); + qt_sendSpontaneousEvent(qwidget, &e); + if (!qwidget->testAttribute(Qt::WA_StaticContents)) + qwidget->d_func()->syncBackingStore(); + if (!slowResize && tlwExtra) + tlwExtra->inTopLevelResize = false; + } else { + if (!qwidget->testAttribute(Qt::WA_PendingResizeEvent)) { + QResizeEvent *e = new QResizeEvent(newSize, oldSize); + QApplication::postEvent(qwidget, e); + } + } +} + void QSymbianControl::SizeChanged() { CCoeControl::SizeChanged(); + // When FixNativeOrientation had been called, the RWindow/CCoeControl size + // and the surface/QWidget size have nothing to do with each other. + if (qwidget->d_func()->fixNativeOrientationCalled) + return; + QSize oldSize = qwidget->size(); QSize newSize(Size().iWidth, Size().iHeight); if (oldSize != newSize) { + // Enforce the proper size for fullscreen widgets on the secondary screen. const bool isFullscreen = qwidget->windowState() & Qt::WindowFullScreen; const int screenNumber = S60->screenNumberForWidget(qwidget); if (!m_inExternalScreenOverride && isFullscreen && screenNumber > 0) { @@ -1243,26 +1318,8 @@ void QSymbianControl::SizeChanged() return; } } - QRect cr = qwidget->geometry(); - cr.setSize(newSize); - qwidget->data->crect = cr; - if (qwidget->isVisible()) { - QTLWExtra *tlwExtra = qwidget->d_func()->maybeTopData(); - bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt(); - if (!slowResize && tlwExtra) - tlwExtra->inTopLevelResize = true; - QResizeEvent e(newSize, oldSize); - qt_sendSpontaneousEvent(qwidget, &e); - if (!qwidget->testAttribute(Qt::WA_StaticContents)) - qwidget->d_func()->syncBackingStore(); - if (!slowResize && tlwExtra) - tlwExtra->inTopLevelResize = false; - } else { - if (!qwidget->testAttribute(Qt::WA_PendingResizeEvent)) { - QResizeEvent *e = new QResizeEvent(newSize, oldSize); - QApplication::postEvent(qwidget, e); - } - } + + qwidgetResize_helper(newSize); } m_inExternalScreenOverride = false; @@ -1513,29 +1570,49 @@ bool QSymbianControl::isControlActive() void QSymbianControl::ensureFixNativeOrientation() { #if defined(Q_SYMBIAN_SUPPORTS_FIXNATIVEORIENTATION) - // Call FixNativeOrientation() for fullscreen QDeclarativeViews that - // have a locked orientation matching the native orientation of the device. - // This avoids unnecessary window rotation on wserv level. - if (!qwidget->isWindow() || qwidget->windowType() == Qt::Desktop - || !qwidget->inherits("QDeclarativeView") - || S60->screenNumberForWidget(qwidget) > 0) + if (!qwidget->isWindow() || qwidget->windowType() == Qt::Desktop) + return; + if (S60->screenNumberForWidget(qwidget) > 0) return; - const bool isFullScreen = qwidget->windowState().testFlag(Qt::WindowFullScreen); const bool isFixed = qwidget->d_func()->fixNativeOrientationCalled; - const bool matchesNative = qwidget->testAttribute( - S60->nativeOrientationIsPortrait ? Qt::WA_LockPortraitOrientation - : Qt::WA_LockLandscapeOrientation); - if (isFullScreen && matchesNative) { - if (!isFixed) { - Window().FixNativeOrientation(); - qwidget->d_func()->fixNativeOrientationCalled = true; + const bool isFixEnabled = qwidget->testAttribute(Qt::WA_SymbianNoSystemRotation); + const bool isFullScreen = qwidget->windowState().testFlag(Qt::WindowFullScreen); + if (isFullScreen && isFixEnabled) { + const bool surfaceBasedGs = + QApplicationPrivate::graphics_system_name == QLatin1String("openvg") + || QApplicationPrivate::graphics_system_name == QLatin1String("opengl"); + if (!surfaceBasedGs) + qwidget->setAttribute(Qt::WA_SymbianNoSystemRotation, false); + if (!isFixed && surfaceBasedGs) { + if (Window().FixNativeOrientation() == KErrNone) { + qwidget->d_func()->fixNativeOrientationCalled = true; + // The EGL window surface is now fixed to the native orientation + // of the device, no matter what size we pass when creating it. + // Enforce the same size for the QWidget too. For the underlying + // CCoeControl and RWindow it is up to the system to resize them + // when the standard auto-rotation mechanism is in use, we must not + // change that behavior by forcing any size for those. In practice + // this means that the QWidget and the underlying native control + // dimensions will be out of sync when FixNativeOrientation was + // called and the device is turned to the non-native (typically + // landscape) orientation. The pointer event handling and certain + // functions like Draw() will need to compensate for this. + QSize newSize(S60->nativeScreenWidthInPixels, S60->nativeScreenHeightInPixels); + if (qwidget->size() != newSize) + qwidgetResize_helper(newSize); + } else { + qwidget->setAttribute(Qt::WA_SymbianNoSystemRotation, false); + } } } else if (isFixed) { + qwidget->setAttribute(Qt::WA_SymbianNoSystemRotation, false); qwidget->d_func()->fixNativeOrientationCalled = false; qwidget->hide(); qwidget->d_func()->create_sys(0, false, true); qwidget->show(); } +#else + qwidget->setAttribute(Qt::WA_SymbianNoSystemRotation, false); #endif } diff --git a/src/gui/kernel/qt_s60_p.h b/src/gui/kernel/qt_s60_p.h index c48bf63..e24405c 100644 --- a/src/gui/kernel/qt_s60_p.h +++ b/src/gui/kernel/qt_s60_p.h @@ -191,7 +191,8 @@ public: int screenWidthInTwipsForScreen[qt_symbian_max_screens]; int screenHeightInTwipsForScreen[qt_symbian_max_screens]; - bool nativeOrientationIsPortrait; + int nativeScreenWidthInPixels; + int nativeScreenHeightInPixels; }; Q_AUTOTEST_EXPORT QS60Data* qGlobalS60Data(); @@ -237,6 +238,8 @@ public: bool isControlActive(); void ensureFixNativeOrientation(); + QPoint translatePointForFixedNativeOrientation(const TPoint &pointerEventPos) const; + TRect translateRectForFixedNativeOrientation(const TRect &controlRect) const; #ifdef Q_WS_S60 void FadeBehindPopup(bool fade){ popupFader.FadeBehindPopup( this, this, fade); } @@ -256,6 +259,9 @@ protected: void PositionChanged(); void FocusChanged(TDrawNow aDrawNow); +protected: + void qwidgetResize_helper(const QSize &newSize); + private: void HandlePointerEvent(const TPointerEvent& aPointerEvent); TKeyResponse OfferKeyEvent(const TKeyEvent& aKeyEvent,TEventCode aType); @@ -363,18 +369,15 @@ inline void QS60Data::updateScreenSize() // Look for a screen mode with rotation 0 // in order to decide what the native orientation is. - int nativeScreenWidthInPixels = 0; - int nativeScreenHeightInPixels = 0; for (mode = 0; mode < screenModeCount; ++mode) { TPixelsAndRotation sizeAndRotation; dev->GetScreenModeSizeAndRotation(mode, sizeAndRotation); if (sizeAndRotation.iRotation == CFbsBitGc::EGraphicsOrientationNormal) { - nativeScreenWidthInPixels = sizeAndRotation.iPixelSize.iWidth; - nativeScreenHeightInPixels = sizeAndRotation.iPixelSize.iHeight; + S60->nativeScreenWidthInPixels = sizeAndRotation.iPixelSize.iWidth; + S60->nativeScreenHeightInPixels = sizeAndRotation.iPixelSize.iHeight; break; } } - S60->nativeOrientationIsPortrait = nativeScreenWidthInPixels <= nativeScreenHeightInPixels; } inline RWsSession& QS60Data::wsSession() diff --git a/src/gui/kernel/qwidget_s60.cpp b/src/gui/kernel/qwidget_s60.cpp index 10bb98b..d55e1ad 100644 --- a/src/gui/kernel/qwidget_s60.cpp +++ b/src/gui/kernel/qwidget_s60.cpp @@ -838,6 +838,8 @@ void QWidgetPrivate::s60UpdateIsOpaque() // recreate backing store to get translucent surface (raster surface). extra->topextra->backingStore.create(q); extra->topextra->backingStore.registerWidget(q); + // FixNativeOrientation() will not work without an EGL surface. + q->setAttribute(Qt::WA_SymbianNoSystemRotation, false); } } } else if (extra->topextra->nativeWindowTransparencyEnabled) { -- cgit v0.12 From 2cafc79ff4b4521a594031cd1db0229aa594f84e Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Tue, 12 Apr 2011 12:51:22 +0200 Subject: Revert "HTTP caching internals: fix logic for PreferNetwork and PreferCache" This reverts commit e5d27e7aeac984e46f3aa8de20160cc00fc63155. Conflicts: tests/auto/qabstractnetworkcache/tst_qabstractnetworkcache.cpp --- src/network/access/qnetworkaccesshttpbackend.cpp | 7 +---- .../tst_qabstractnetworkcache.cpp | 33 +++++++++------------- 2 files changed, 15 insertions(+), 25 deletions(-) diff --git a/src/network/access/qnetworkaccesshttpbackend.cpp b/src/network/access/qnetworkaccesshttpbackend.cpp index b0ca9e0..9de5d84 100644 --- a/src/network/access/qnetworkaccesshttpbackend.cpp +++ b/src/network/access/qnetworkaccesshttpbackend.cpp @@ -263,11 +263,6 @@ bool QNetworkAccessHttpBackend::loadFromCacheIfAllowed(QHttpNetworkRequest &http httpRequest.setHeaderField("If-Modified-Since", QNetworkHeadersPrivate::toHttpDate(lastModified)); if (CacheLoadControlAttribute == QNetworkRequest::PreferNetwork) { - // PreferNetwork == send request with "If-None-Match" and "If-Modified-Since" header, - // which will return a 304 Not Modifed if resource has not been changed. - // We might read from cache later, if receiving a 304. - return false; - } else if (CacheLoadControlAttribute == QNetworkRequest::PreferCache) { it = cacheHeaders.findRawHeader("Cache-Control"); if (it != cacheHeaders.rawHeaders.constEnd()) { QHash cacheControl = parseHttpOptionHeader(it->second); @@ -1156,7 +1151,7 @@ QNetworkCacheMetaData QNetworkAccessHttpBackend::fetchCacheMetaData(const QNetwo attributes.insert(QNetworkRequest::HttpStatusCodeAttribute, statusCode); attributes.insert(QNetworkRequest::HttpReasonPhraseAttribute, reasonPhrase); } else { - // this is the server telling us the resource has not changed, keep the attributes intact + // this is a redirection, keep the attributes intact attributes = oldMetaData.attributes(); } metaData.setAttributes(attributes); diff --git a/tests/auto/qabstractnetworkcache/tst_qabstractnetworkcache.cpp b/tests/auto/qabstractnetworkcache/tst_qabstractnetworkcache.cpp index 4a66d4d..da57d1b 100644 --- a/tests/auto/qabstractnetworkcache/tst_qabstractnetworkcache.cpp +++ b/tests/auto/qabstractnetworkcache/tst_qabstractnetworkcache.cpp @@ -156,19 +156,16 @@ void tst_QAbstractNetworkCache::expires_data() // Server sending Expires header, QTest::addColumn("url"); QTest::addColumn("fetchFromCache"); - // httpcachetest_expires304.cgi will send a 304 upon receiving a If-Modified-Since header QTest::newRow("304-0") << QNetworkRequest::AlwaysNetwork << "httpcachetest_expires304.cgi" << AlwaysFalse; - QTest::newRow("304-1") << QNetworkRequest::PreferNetwork << "httpcachetest_expires304.cgi" << false; // neither Last-Modified nor ETag given + QTest::newRow("304-1") << QNetworkRequest::PreferNetwork << "httpcachetest_expires304.cgi" << true; QTest::newRow("304-2") << QNetworkRequest::AlwaysCache << "httpcachetest_expires304.cgi" << AlwaysTrue; - QTest::newRow("304-3") << QNetworkRequest::PreferCache << "httpcachetest_expires304.cgi" << true; // we know the expiration date, so we can read from cache + QTest::newRow("304-3") << QNetworkRequest::PreferCache << "httpcachetest_expires304.cgi" << true; - // httpcachetest_expires500.cgi will send a 500 upon receiving a If-Modified-Since header QTest::newRow("500-0") << QNetworkRequest::AlwaysNetwork << "httpcachetest_expires500.cgi" << AlwaysFalse; - QTest::newRow("500-1") << QNetworkRequest::PreferNetwork << "httpcachetest_expires500.cgi" << false; // neither Last-Modified nor ETag given + QTest::newRow("500-1") << QNetworkRequest::PreferNetwork << "httpcachetest_expires500.cgi" << true; QTest::newRow("500-2") << QNetworkRequest::AlwaysCache << "httpcachetest_expires500.cgi" << AlwaysTrue; - QTest::newRow("500-3") << QNetworkRequest::PreferCache << "httpcachetest_expires500.cgi" << true; // we know the expiration date, so we can read from cache + QTest::newRow("500-3") << QNetworkRequest::PreferCache << "httpcachetest_expires500.cgi" << true; - // httpcachetest_expires200.cgi will always send a 200 header QTest::newRow("200-0") << QNetworkRequest::AlwaysNetwork << "httpcachetest_expires200.cgi" << AlwaysFalse; QTest::newRow("200-1") << QNetworkRequest::PreferNetwork << "httpcachetest_expires200.cgi" << false; QTest::newRow("200-2") << QNetworkRequest::AlwaysCache << "httpcachetest_expires200.cgi" << AlwaysTrue; @@ -196,17 +193,15 @@ void tst_QAbstractNetworkCache::lastModified_data() QTest::addColumn("url"); QTest::addColumn("fetchFromCache"); - // httpcachetest_lastModified304.cgi will send a 304 upon receiving a If-Modified-Since header QTest::newRow("304-0") << QNetworkRequest::AlwaysNetwork << "httpcachetest_lastModified304.cgi" << AlwaysFalse; - QTest::newRow("304-1") << QNetworkRequest::PreferNetwork << "httpcachetest_lastModified304.cgi" << true; // we know the last modified date, so we can send If-Modified-Since and get 304, then we can read from cache + QTest::newRow("304-1") << QNetworkRequest::PreferNetwork << "httpcachetest_lastModified304.cgi" << true; QTest::newRow("304-2") << QNetworkRequest::AlwaysCache << "httpcachetest_lastModified304.cgi" << AlwaysTrue; - QTest::newRow("304-3") << QNetworkRequest::PreferCache << "httpcachetest_lastModified304.cgi" << true; // we know the last modified date, so we can send If-Modified-Since and get 304, then we can read from cache + QTest::newRow("304-3") << QNetworkRequest::PreferCache << "httpcachetest_lastModified304.cgi" << true; - // httpcachetest_lastModified200.cgi will always send a 200 header QTest::newRow("200-0") << QNetworkRequest::AlwaysNetwork << "httpcachetest_lastModified200.cgi" << AlwaysFalse; - QTest::newRow("200-1") << QNetworkRequest::PreferNetwork << "httpcachetest_lastModified200.cgi" << false; // we won't get a 304 (although sending If-Modified-Since), so we cannot read from cache + QTest::newRow("200-1") << QNetworkRequest::PreferNetwork << "httpcachetest_lastModified200.cgi" << false; QTest::newRow("200-2") << QNetworkRequest::AlwaysCache << "httpcachetest_lastModified200.cgi" << AlwaysTrue; - QTest::newRow("200-3") << QNetworkRequest::PreferCache << "httpcachetest_lastModified200.cgi" << false; // we won't get a 304 (although sending If-Modified-Since), so we cannot read from cache + QTest::newRow("200-3") << QNetworkRequest::PreferCache << "httpcachetest_lastModified200.cgi" << false; } void tst_QAbstractNetworkCache::lastModified() @@ -231,14 +226,14 @@ void tst_QAbstractNetworkCache::etag_data() QTest::addColumn("fetchFromCache"); QTest::newRow("304-0") << QNetworkRequest::AlwaysNetwork << "httpcachetest_etag304.cgi" << AlwaysFalse; - QTest::newRow("304-1") << QNetworkRequest::PreferNetwork << "httpcachetest_etag304.cgi" << true; // we will send If-None-Match and get 304 + QTest::newRow("304-1") << QNetworkRequest::PreferNetwork << "httpcachetest_etag304.cgi" << true; QTest::newRow("304-2") << QNetworkRequest::AlwaysCache << "httpcachetest_etag304.cgi" << AlwaysTrue; - QTest::newRow("304-3") << QNetworkRequest::PreferCache << "httpcachetest_etag304.cgi" << true; // we don't have expiration information, but will get 304, as with PreferNetwork + QTest::newRow("304-3") << QNetworkRequest::PreferCache << "httpcachetest_etag304.cgi" << true; QTest::newRow("200-0") << QNetworkRequest::AlwaysNetwork << "httpcachetest_etag200.cgi" << AlwaysFalse; - QTest::newRow("200-1") << QNetworkRequest::PreferNetwork << "httpcachetest_etag200.cgi" << false; // we will send If-None-Match and get 200 + QTest::newRow("200-1") << QNetworkRequest::PreferNetwork << "httpcachetest_etag200.cgi" << false; QTest::newRow("200-2") << QNetworkRequest::AlwaysCache << "httpcachetest_etag200.cgi" << AlwaysTrue; - QTest::newRow("200-3") << QNetworkRequest::PreferCache << "httpcachetest_etag200.cgi" << false; // we don't have expiration information, and will get 200, as with PreferNetwork + QTest::newRow("200-3") << QNetworkRequest::PreferCache << "httpcachetest_etag200.cgi" << false; } void tst_QAbstractNetworkCache::etag() @@ -278,8 +273,8 @@ void tst_QAbstractNetworkCache::cacheControl_data() // see QTBUG-7060 //QTest::newRow("nokia-boston") << QNetworkRequest::PreferNetwork << "http://waplabdc.nokia-boston.com/browser/users/venkat/cache/Cache_directives/private_1b.asp" << true; - QTest::newRow("304-2b") << QNetworkRequest::PreferNetwork << "httpcachetest_cachecontrol200.cgi?private, max-age=1000" << false; // script always returns 200, so we cannot load from cache - QTest::newRow("304-4b") << QNetworkRequest::PreferCache << "httpcachetest_cachecontrol200.cgi?private, max-age=1000" << true; // we got expiry information + QTest::newRow("304-2b") << QNetworkRequest::PreferNetwork << "httpcachetest_cachecontrol200.cgi?private, max-age=1000" << true; + QTest::newRow("304-4b") << QNetworkRequest::PreferCache << "httpcachetest_cachecontrol200.cgi?private, max-age=1000" << true; } void tst_QAbstractNetworkCache::cacheControl() -- cgit v0.12 From 61e7617f4afdd5cc1956de9ee2c7172ba95956d0 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 12 Apr 2011 12:14:15 +0100 Subject: Fix regression with Qt::AutoConnection Change df9491b302f6404ad2ccc6dc2eb3377176d994c6 optimised auto connections by comparing thread ID rather than comparing TLS addresses. However it was implemented on a branch that didn't have the native symbian threads. So merging the two branches caused a regression without merge conflicts. Reviewed-by: mread --- src/corelib/thread/qthread_symbian.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/corelib/thread/qthread_symbian.cpp b/src/corelib/thread/qthread_symbian.cpp index 1474b36..15e6898 100644 --- a/src/corelib/thread/qthread_symbian.cpp +++ b/src/corelib/thread/qthread_symbian.cpp @@ -113,6 +113,7 @@ QThreadData *QThreadData::current() } data->deref(); } + data->threadId = QThread::currentThreadId(); if (!QCoreApplicationPrivate::theMainThread) QCoreApplicationPrivate::theMainThread = data->thread; } @@ -312,6 +313,7 @@ void *QThreadPrivate::start(void *arg) // attribute of the thread again once the app gains control in run() User::SetCritical(User::EProcessCritical); + data->threadId = QThread::currentThreadId(); set_thread_data(data); { -- cgit v0.12 From 60475e93890550f4fb67367980249a21b9346747 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Tue, 12 Apr 2011 14:27:15 +0200 Subject: Have the backing store destroyed also in special Symbian scenarios. The backing store tracker's registerWidget and unregisterWidget functions are called when EPartiallyVisible and ENotVisible events come from WSERV. However if an application sends its window group to background right after caling show() and before entering the event loop, there is a chance that all the application will receive is an ENotVisible event, leading to calling unregisterWidget() without a previous registerWidget(). In this case the backing store was not destroyed and the application was consuming GPU memory even while it was staying in background. This patch ensures registerWidget() is called always before unregisterWidget() in the Symbian-specific event handler for ENotVisible, and replaces the previous patch, a12d41076919a133e63de63dff5c1a131a0564e4, which caused regression in autotests. Task-number: QTBUG-18493 Reviewed-by: Gareth Stockwell --- src/gui/kernel/qapplication_s60.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index d37845d..f73eb02 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -215,6 +215,12 @@ void QS60Data::controlVisibilityChanged(CCoeControl *control, bool visible) widget->repaint(); } } else { + // In certain special scenarios we may get an ENotVisible event + // without a previous EPartiallyVisible. The backingstore must + // still be destroyed, hence the registerWidget() call below. + if (backingStore.data() && widget->internalWinId() + && qt_widget_private(widget)->maybeBackingStore() == backingStore.data()) + backingStore.registerWidget(widget); backingStore.unregisterWidget(widget); // In order to ensure that any resources used by the window surface // are immediately freed, we flush the WSERV command buffer. -- cgit v0.12 From 46163663e956b988719563eae18773a2dedd424e Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Tue, 12 Apr 2011 14:48:13 +0200 Subject: Added support for libICU for collation and toLower/toUpper. This patch uses icu to do string collation via QString::localeAwareCompare function and for QString::toLower/toUpper - which is important e.g. for turkish locales where uppercased 'i' is not a latin 'I'. Based on the patch by Harald Fernengel Reviewed-by: Harald Fernengel Reviewed-by: Zeno Albisser --- config.tests/unix/icu/icu.cpp | 54 +++++++++ config.tests/unix/icu/icu.pro | 4 + configure | 34 +++++- src/corelib/tools/qlocale.cpp | 14 +++ src/corelib/tools/qlocale_icu.cpp | 224 +++++++++++++++++++++++++++++++++++++ src/corelib/tools/qstring.cpp | 35 +++++- src/corelib/tools/tools.pri | 5 + tests/auto/qstring/qstring.pro | 2 + tests/auto/qstring/tst_qstring.cpp | 55 +++++++++ 9 files changed, 425 insertions(+), 2 deletions(-) create mode 100644 config.tests/unix/icu/icu.cpp create mode 100644 config.tests/unix/icu/icu.pro create mode 100644 src/corelib/tools/qlocale_icu.cpp diff --git a/config.tests/unix/icu/icu.cpp b/config.tests/unix/icu/icu.cpp new file mode 100644 index 0000000..f03b160 --- /dev/null +++ b/config.tests/unix/icu/icu.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the config.tests 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 +#include +#include + +int main(int, char **) +{ + UErrorCode status = U_ZERO_ERROR; + UCollator *collator = ucol_open("ru_RU", &status); + if (U_FAILURE(status)) + return 0; + ucol_close(collator); + return 0; +} diff --git a/config.tests/unix/icu/icu.pro b/config.tests/unix/icu/icu.pro new file mode 100644 index 0000000..8e58334 --- /dev/null +++ b/config.tests/unix/icu/icu.pro @@ -0,0 +1,4 @@ +SOURCES = icu.cpp +CONFIG -= qt dylib app_bundle +unix:LIBS += -licuuc -licui18n +win32:LIBS += -licuin diff --git a/configure b/configure index 4d25ec2..bf67205 100755 --- a/configure +++ b/configure @@ -832,6 +832,7 @@ CFG_PULSEAUDIO=auto CFG_COREWLAN=auto CFG_ICD=auto CFG_NOPROCESS=no +CFG_ICU=auto # initalize variables used for installation QT_INSTALL_PREFIX= @@ -1040,7 +1041,7 @@ while [ "$#" -gt 0 ]; do VAL=no ;; #Qt style yes options - -incremental|-qvfb|-profile|-shared|-static|-sm|-xinerama|-xshape|-xsync|-xinput|-egl|-reduce-exports|-pch|-separate-debug-info|-stl|-freetype|-xcursor|-xfixes|-xrandr|-xrender|-mitshm|-fontconfig|-xkb|-nis|-qdbus|-dbus|-dbus-linked|-glib|-gstreamer|-gtkstyle|-cups|-iconv|-largefile|-h|-help|-v|-verbose|-debug|-release|-fast|-accessibility|-confirm-license|-gnumake|-framework|-qt3support|-debug-and-release|-exceptions|-cocoa|-carbon|-universal|-prefix-install|-silent|-armfpa|-optimized-qmake|-dwarf2|-reduce-relocations|-sse|-openssl|-openssl-linked|-ptmalloc|-xmlpatterns|-phonon|-phonon-backend|-multimedia|-audio-backend|-svg|-declarative|-declarative-debug|-javascript-jit|-script|-scripttools|-rpath|-force-pkg-config|-s60|-usedeffiles) + -incremental|-qvfb|-profile|-shared|-static|-sm|-xinerama|-xshape|-xsync|-xinput|-egl|-reduce-exports|-pch|-separate-debug-info|-stl|-freetype|-xcursor|-xfixes|-xrandr|-xrender|-mitshm|-fontconfig|-xkb|-nis|-qdbus|-dbus|-dbus-linked|-glib|-gstreamer|-gtkstyle|-cups|-iconv|-largefile|-h|-help|-v|-verbose|-debug|-release|-fast|-accessibility|-confirm-license|-gnumake|-framework|-qt3support|-debug-and-release|-exceptions|-cocoa|-carbon|-universal|-prefix-install|-silent|-armfpa|-optimized-qmake|-dwarf2|-reduce-relocations|-sse|-openssl|-openssl-linked|-ptmalloc|-xmlpatterns|-phonon|-phonon-backend|-multimedia|-audio-backend|-svg|-declarative|-declarative-debug|-javascript-jit|-script|-scripttools|-rpath|-force-pkg-config|-s60|-usedeffiles|-icu) VAR=`echo $1 | sed "s,^-\(.*\),\1,"` VAL=yes ;; @@ -2376,6 +2377,13 @@ while [ "$#" -gt 0 ]; do QT_CFLAGS_FPU=$VAL fi ;; + icu) + if [ "$VAL" = "yes" ] || [ "$VAL" = "no" ]; then + CFG_ICU="$VAL" + else + UNKNOWN_OPT=yes + fi + ;; *) UNKNOWN_OPT=yes ;; @@ -5679,6 +5687,25 @@ if [ "$PLATFORM_X11" = "yes" -o "$PLATFORM_QWS" = "yes" -o "$PLATFORM_QPA" = "ye CFG_ICD=no fi + # auto-detect libicu support + if [ "$CFG_ICU" != "no" ]; then + if "$unixtests/compile.test" "$XQMAKESPEC" "$QMAKE_CONFIG" $OPT_VERBOSE "$relpath" "$outpath" config.tests/unix/icu "ICU" $L_FLAGS $I_FLAGS $l_FLAGS; then + [ "$CFG_ICU" = "auto" ] && CFG_ICU=yes + else + if [ "$CFG_ICU" = "auto" ]; then + CFG_ICU=no + elif [ "$CFG_CONFIGURE_EXIT_ON_ERROR" = "yes" ]; then + # CFG_ICU is "yes" + + echo "The ICU library support cannot be enabled." + echo " Turn on verbose messaging (-v) to $0 to see the final report." + echo " If you believe this message is in error you may use the continue" + echo " switch (-continue) to $0 to continue." + exit 101 + fi + fi + fi + # Auto-detect PulseAudio support if [ "$CFG_PULSEAUDIO" != "no" ]; then if [ -n "$PKG_CONFIG" ]; then @@ -7337,6 +7364,10 @@ if [ "$CFG_ICD" = "yes" ]; then QT_CONFIG="$QT_CONFIG icd" fi +if [ "$CFG_ICU" = "yes" ]; then + QT_CONFIG="$QT_CONFIG icu" +fi + # # Some Qt modules are too advanced in C++ for some old compilers # Detect here the platforms where they are known to work. @@ -8727,6 +8758,7 @@ if [ "$PLATFORM_MAC" = "yes" ]; then echo "CoreWlan support ....... $CFG_COREWLAN" fi echo "ICD support ............ $CFG_ICD" +echo "libICU support ......... $CFG_ICU" echo [ "$CFG_PTMALLOC" != "no" ] && echo "Use ptmalloc ........... $CFG_PTMALLOC" diff --git a/src/corelib/tools/qlocale.cpp b/src/corelib/tools/qlocale.cpp index d986b9b..5c4085a 100644 --- a/src/corelib/tools/qlocale.cpp +++ b/src/corelib/tools/qlocale.cpp @@ -86,6 +86,10 @@ static QLocalePrivate *system_lp = 0; Q_GLOBAL_STATIC(QLocalePrivate, globalLocalePrivate) #endif +#ifdef QT_USE_ICU +extern bool qt_initIcu(const QString &localeName); +#endif + /****************************************************************************** ** Helpers for accessing Qt locale database */ @@ -520,6 +524,12 @@ void QLocalePrivate::updateSystemPrivate() res = sys_locale->query(QSystemLocale::PositiveSign, QVariant()); if (!res.isNull()) system_lp->m_plus = res.toString().at(0).unicode(); + +#ifdef QT_USE_ICU + if (!default_lp) + qt_initIcu(system_lp->bcp47Name()); +#endif + } #endif @@ -879,6 +889,10 @@ void QLocale::setDefault(const QLocale &locale) { default_lp = locale.d(); default_number_options = locale.numberOptions(); + +#ifdef QT_USE_ICU + qt_initIcu(locale.bcp47Name()); +#endif } /*! diff --git a/src/corelib/tools/qlocale_icu.cpp b/src/corelib/tools/qlocale_icu.cpp new file mode 100644 index 0000000..0e283dd --- /dev/null +++ b/src/corelib/tools/qlocale_icu.cpp @@ -0,0 +1,224 @@ +/**************************************************************************** +** +** 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 QtCore 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 "qglobal.h" +#include "qlibrary.h" +#include "qdebug.h" + +#include "unicode/uversion.h" +#include "unicode/ucol.h" + +QT_BEGIN_NAMESPACE + +typedef UCollator *(*Ptr_ucol_open)(const char *loc, UErrorCode *status); +typedef void (*Ptr_ucol_close)(UCollator *coll); +typedef UCollationResult (*Ptr_ucol_strcoll)(const UCollator *coll, const UChar *source, int32_t sourceLength, const UChar *target, int32_t targetLength); +typedef int32_t (*Ptr_u_strToCase)(UChar *dest, int32_t destCapacity, const UChar *src, int32_t srcLength, const char *locale, UErrorCode *pErrorCode); + +static Ptr_ucol_open ptr_ucol_open = 0; +static Ptr_ucol_strcoll ptr_ucol_strcoll = 0; +static Ptr_ucol_close ptr_ucol_close = 0; +static Ptr_u_strToCase ptr_u_strToUpper = 0; +static Ptr_u_strToCase ptr_u_strToLower = 0; + +enum LibLoadStatus +{ + ErrorLoading = -1, + NotLoaded = 0, + Loaded = 1 +}; + +static LibLoadStatus status = NotLoaded; + +static UCollator *icuCollator = 0; + +#define STRINGIFY2(x) #x +#define STRINGIFY(x) STRINGIFY2(x) + +bool qt_initIcu(const QString &localeString) +{ + if (status == ErrorLoading) + return false; + + if (status == NotLoaded) { + + // resolve libicui18n + QLibrary lib(QLatin1String("icui18n"), QLatin1String(U_ICU_VERSION_SHORT)); + if (!lib.load()) { + qWarning() << "Unable to load library icui18n" << lib.errorString(); + status = ErrorLoading; + return false; + } + + ptr_ucol_open = (Ptr_ucol_open)lib.resolve("ucol_open"); + ptr_ucol_close = (Ptr_ucol_close)lib.resolve("ucol_close"); + ptr_ucol_strcoll = (Ptr_ucol_strcoll)lib.resolve("ucol_strcoll"); + + if (!ptr_ucol_open || !ptr_ucol_close || !ptr_ucol_strcoll) { + // try again with decorated symbol names + ptr_ucol_open = (Ptr_ucol_open)lib.resolve("ucol_open" STRINGIFY(U_ICU_VERSION_SUFFIX)); + ptr_ucol_close = (Ptr_ucol_close)lib.resolve("ucol_close" STRINGIFY(U_ICU_VERSION_SUFFIX)); + ptr_ucol_strcoll = (Ptr_ucol_strcoll)lib.resolve("ucol_strcoll" STRINGIFY(U_ICU_VERSION_SUFFIX)); + } + + if (!ptr_ucol_open || !ptr_ucol_close || !ptr_ucol_strcoll) { + ptr_ucol_open = 0; + ptr_ucol_close = 0; + ptr_ucol_strcoll = 0; + + qWarning("Unable to find symbols in icui18n"); + status = ErrorLoading; + return false; + } + + // resolve libicuuc + QLibrary ucLib(QLatin1String("icuuc"), QLatin1String(U_ICU_VERSION_SHORT)); + if (!ucLib.load()) { + qWarning() << "Unable to load library icuuc" << ucLib.errorString(); + status = ErrorLoading; + return false; + } + + ptr_u_strToUpper = (Ptr_u_strToCase)ucLib.resolve("u_strToUpper"); + ptr_u_strToLower = (Ptr_u_strToCase)ucLib.resolve("u_strToLower"); + + if (!ptr_u_strToUpper || !ptr_u_strToLower) { + ptr_u_strToUpper = (Ptr_u_strToCase)ucLib.resolve("u_strToUpper" STRINGIFY(U_ICU_VERSION_SUFFIX)); + ptr_u_strToLower = (Ptr_u_strToCase)ucLib.resolve("u_strToLower" STRINGIFY(U_ICU_VERSION_SUFFIX)); + } + + if (!ptr_u_strToUpper || !ptr_u_strToLower) { + ptr_u_strToUpper = 0; + ptr_u_strToLower = 0; + + qWarning("Unable to find symbols in icuuc"); + status = ErrorLoading; + return false; + } + + // success :) + status = Loaded; + } + + if (icuCollator) { + ptr_ucol_close(icuCollator); + icuCollator = 0; + } + + UErrorCode icuStatus = U_ZERO_ERROR; + icuCollator = ptr_ucol_open(localeString.toLatin1().constData(), &icuStatus); + + if (!icuCollator) { + qWarning("Unable to open locale %s in ICU, error code %d", qPrintable(localeString), icuStatus); + return false; + } + + return true; +} + +bool qt_ucol_strcoll(const QChar *source, int sourceLength, const QChar *target, int targetLength, int *result) +{ + Q_ASSERT(result); + Q_ASSERT(source); + Q_ASSERT(target); + + if (!icuCollator) + return false; + + *result = ptr_ucol_strcoll(icuCollator, reinterpret_cast(source), int32_t(sourceLength), + reinterpret_cast(target), int32_t(targetLength)); + + return true; +} + +// caseFunc can either be u_strToUpper or u_strToLower +static bool qt_u_strToCase(const QString &str, QString *out, const QLocale &locale, Ptr_u_strToCase caseFunc) +{ + Q_ASSERT(out); + + if (!icuCollator) + return false; + + QString result(str.size(), Qt::Uninitialized); + + UErrorCode status = U_ZERO_ERROR; + + int32_t size = caseFunc(reinterpret_cast(result.data()), result.size(), + reinterpret_cast(str.constData()), str.size(), + locale.bcp47Name().toLatin1().constData(), &status); + + if (U_FAILURE(status)) + return false; + + if (size < result.size()) { + result.resize(size); + } else if (size > result.size()) { + // the resulting string is larger than our source string + result.resize(size); + + status = U_ZERO_ERROR; + size = caseFunc(reinterpret_cast(result.data()), result.size(), + reinterpret_cast(str.constData()), str.size(), + locale.bcp47Name().toLatin1().constData(), &status); + + if (U_FAILURE(status)) + return false; + + // if the sizes don't match now, we give up. + if (size != result.size()) + return false; + } + + *out = result; + return true; +} + +bool qt_u_strToUpper(const QString &str, QString *out, const QLocale &locale) +{ + return qt_u_strToCase(str, out, locale, ptr_u_strToUpper); +} + +bool qt_u_strToLower(const QString &str, QString *out, const QLocale &locale) +{ + return qt_u_strToCase(str, out, locale, ptr_u_strToLower); +} + +QT_END_NAMESPACE diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index b7272ec..5493ba9 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -106,6 +106,14 @@ QTextCodec *QString::codecForCStrings; static QHash *asciiCache = 0; #endif +#ifdef QT_USE_ICU +// qlocale_icu.cpp +extern bool qt_ucol_strcoll(const QChar *source, int sourceLength, const QChar *target, int targetLength, int *result); +extern bool qt_u_strToUpper(const QString &str, QString *out, const QLocale &locale); +extern bool qt_u_strToLower(const QString &str, QString *out, const QLocale &locale); +#endif + + // internal int qFindString(const QChar *haystack, int haystackLen, int from, const QChar *needle, int needleLen, Qt::CaseSensitivity cs); @@ -431,7 +439,6 @@ const QString::Null QString::null = { }; \ingroup shared \ingroup string-processing - QString stores a string of 16-bit \l{QChar}s, where each QChar corresponds one Unicode 4.0 character. (Unicode characters with code values above 65535 are stored using surrogate pairs, @@ -4829,6 +4836,14 @@ int QString::localeAwareCompare_helper(const QChar *data1, int length1, TPtrC p2 = TPtrC16(reinterpret_cast(data2), length2); return p1.CompareC(p2); #elif defined(Q_OS_UNIX) +# if defined(QT_USE_ICU) + int res; + if (qt_ucol_strcoll(data1, length1, data2, length2, &res)) { + if (res == 0) + res = ucstrcmp(data1, length1, data2, length2); + return res; + } // else fall through +# endif // declared in int delta = strcoll(toLocal8Bit_helper(data1, length1), toLocal8Bit_helper(data2, length2)); if (delta == 0) @@ -4964,6 +4979,15 @@ QString QString::toLower() const if (!d->size) return *this; +#ifdef QT_USE_ICU + { + QString result; + if (qt_u_strToLower(*this, &result, QLocale())) + return result; + // else fall through and use Qt's toUpper + } +#endif + const ushort *e = d->data + d->size; // this avoids one out of bounds check in the loop @@ -5055,6 +5079,15 @@ QString QString::toUpper() const if (!d->size) return *this; +#ifdef QT_USE_ICU + { + QString result; + if (qt_u_strToUpper(*this, &result, QLocale())) + return result; + // else fall through and use Qt's toUpper + } +#endif + const ushort *e = d->data + d->size; // this avoids one out of bounds check in the loop diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri index 849dc63..0c2cf16 100644 --- a/src/corelib/tools/tools.pri +++ b/src/corelib/tools/tools.pri @@ -97,6 +97,11 @@ else:SOURCES += tools/qelapsedtimer_generic.cpp contains(QT_CONFIG, zlib):include($$PWD/../../3rdparty/zlib.pri) else:include($$PWD/../../3rdparty/zlib_dependency.pri) +contains(QT_CONFIG,icu) { + SOURCES += tools/qlocale_icu.cpp + DEFINES += QT_USE_ICU +} + DEFINES += HB_EXPORT=Q_CORE_EXPORT INCLUDEPATH += ../3rdparty/harfbuzz/src HEADERS += ../3rdparty/harfbuzz/src/harfbuzz.h diff --git a/tests/auto/qstring/qstring.pro b/tests/auto/qstring/qstring.pro index e980042..1c123ad 100644 --- a/tests/auto/qstring/qstring.pro +++ b/tests/auto/qstring/qstring.pro @@ -7,3 +7,5 @@ QT = core DEFINES += QT_NO_CAST_TO_ASCII CONFIG += parallel_test + +contains(QT_CONFIG,icu):DEFINES += QT_USE_ICU diff --git a/tests/auto/qstring/tst_qstring.cpp b/tests/auto/qstring/tst_qstring.cpp index 25e16fe..3d80e80 100644 --- a/tests/auto/qstring/tst_qstring.cpp +++ b/tests/auto/qstring/tst_qstring.cpp @@ -222,6 +222,8 @@ private slots: void task262677remove(); void QTBUG10404_compareRef(); void QTBUG9281_arg_locale(); + + void toUpperLower_icu(); }; typedef QList IntList; @@ -1603,6 +1605,11 @@ void tst_QString::toUpper() QCOMPARE( lower.toUpper(), upper); +#ifdef QT_USE_ICU + // test doesn't work with ICU support, since QChar is unaware of any locale + QEXPECT_FAIL("", "test doesn't work with ICU support, since QChar is unaware of any locale", Continue); + QVERIFY(false); +#else for (int i = 0; i < 65536; ++i) { QString str(1, QChar(i)); QString upper = str.toUpper(); @@ -1610,6 +1617,7 @@ void tst_QString::toUpper() if (upper.length() == 1) QVERIFY(upper == QString(1, QChar(i).toUpper())); } +#endif } void tst_QString::toLower() @@ -1641,6 +1649,11 @@ void tst_QString::toLower() upper += QChar(QChar::lowSurrogate(0x10400)); QCOMPARE( upper.toLower(), lower); +#ifdef QT_USE_ICU + // test doesn't work with ICU support, since QChar is unaware of any locale + QEXPECT_FAIL("", "test doesn't work with ICU support, since QChar is unaware of any locale", Continue); + QVERIFY(false); +#else for (int i = 0; i < 65536; ++i) { QString str(1, QChar(i)); QString lower = str.toLower(); @@ -1648,6 +1661,7 @@ void tst_QString::toLower() if (lower.length() == 1) QVERIFY(str.toLower() == QString(1, QChar(i).toLower())); } +#endif } void tst_QString::trimmed() @@ -4352,6 +4366,8 @@ void tst_QString::localeAwareCompare() #elif defined (Q_WS_MAC) QSKIP("Setting the locale is not supported on OS X (you can set the C locale, but that won't affect CFStringCompare which is used to compare strings)", SkipAll); +#elif defined(QT_USE_ICU) + QLocale::setDefault(QLocale(locale)); #else if (!locale.isEmpty()) { const char *newLocale = setlocale(LC_ALL, locale.toLatin1()); @@ -4363,6 +4379,11 @@ void tst_QString::localeAwareCompare() } #endif +#ifdef QT_USE_ICU + // ### for c1, ICU disagrees with libc on how to compare + QEXPECT_FAIL("c1", "ICU disagrees with test", Abort); +#endif + int testres = QString::localeAwareCompare(s1, s2); if (result < 0) { QVERIFY(testres < 0); @@ -5065,6 +5086,40 @@ void tst_QString::QTBUG9281_arg_locale() QLocale::setDefault(QLocale::C); } +void tst_QString::toUpperLower_icu() +{ +#ifndef QT_USE_ICU + QSKIP("Qt was built without ICU support", SkipAll); +#endif + + QString s = QString::fromLatin1("i"); + + QCOMPARE(s.toUpper(), QString::fromLatin1("I")); + QCOMPARE(s.toLower(), QString::fromLatin1("i")); + + QLocale::setDefault(QLocale(QLocale::Turkish, QLocale::Turkey)); + + // turkish locale has a capital I with a dot (U+0130, utf8 c4b0) + + QCOMPARE(s.toUpper(), QString::fromUtf8("\xc4\xb0")); + QCOMPARE(QString::fromUtf8("\xc4\xb0").toLower(), s); + + // nothing should happen here + QCOMPARE(s.toLower(), s); + QCOMPARE(QString::fromLatin1("I").toUpper(), QString::fromLatin1("I")); + + // U+0131, utf8 c4b1 is the lower-case i without a dot + QString sup = QString::fromUtf8("\xc4\xb1"); + + QCOMPARE(sup.toUpper(), QString::fromLatin1("I")); + QCOMPARE(QString::fromLatin1("I").toLower(), sup); + + // nothing should happen here + QCOMPARE(sup.toLower(), sup); + QCOMPARE(QString::fromLatin1("i").toLower(), QString::fromLatin1("i")); + + // the cleanup function will restore the default locale +} QTEST_APPLESS_MAIN(tst_QString) -- cgit v0.12 From 6f1efe75dac53377b92d779818b43a34add92f02 Mon Sep 17 00:00:00 2001 From: mread Date: Tue, 12 Apr 2011 15:07:11 +0100 Subject: Applying the QTBUG-17986 fix to Symbian This change takes the QTBUG-17986 fix, which deletes QThreadData for adopted threads that have created QEventLoops, and applies it to qthread_symbian.cpp, which didn't exist at the time of the original fix. One complication is that Symbian uses a separate thread to monitor adopted thread lifetime, as there is no API to intercept thread exit to have cleanup code run within the context of the thread. However the cleanup for the thread involes deleting active objects that were created in the adopted thread, not the monitor thread. If these active objects are completed but not run, their cancellation could deadlock. In particular the wake up active object in the event dispatcher is typically in this state. We deal with it by detecting the situation and re-completing/cancelling the active object in the adopted thread monitor thread, which prevents deadlock and allows correct operation of the monitor thread. It is possible for this problem to affect other active objects owned by the event dispatcher. They symptom would be that finished signals from adopted threads are not sent, or they arrive much later than they should. Task-number: QTBUG-18622 Reviewed-by: Shane Kearns --- src/corelib/kernel/qeventdispatcher_symbian.cpp | 10 ++++++++++ src/corelib/kernel/qeventdispatcher_symbian_p.h | 3 +++ src/corelib/thread/qthread_symbian.cpp | 8 ++++++++ 3 files changed, 21 insertions(+) diff --git a/src/corelib/kernel/qeventdispatcher_symbian.cpp b/src/corelib/kernel/qeventdispatcher_symbian.cpp index 79f2596..471028e 100644 --- a/src/corelib/kernel/qeventdispatcher_symbian.cpp +++ b/src/corelib/kernel/qeventdispatcher_symbian.cpp @@ -194,6 +194,7 @@ void QActiveObject::reactivateAndComplete() QWakeUpActiveObject::QWakeUpActiveObject(QEventDispatcherSymbian *dispatcher) : QActiveObject(WAKE_UP_PRIORITY, dispatcher) { + m_hostThreadId = RThread().Id(); CActiveScheduler::Add(this); iStatus = KRequestPending; SetActive(); @@ -209,6 +210,15 @@ void QWakeUpActiveObject::DoCancel() if (iStatus.Int() == KRequestPending) { TRequestStatus *status = &iStatus; QEventDispatcherSymbian::RequestComplete(status, KErrNone); + } else if (IsActive() && m_hostThreadId != RThread().Id()) { + // This is being cancelled in the adopted monitor thread, which can happen if an adopted thread with + // an event loop has exited. The event loop creates an event dispatcher with this active object, which may be complete but not run on exit. + // We force a cancellation in this thread, because a) the object cannot be deleted while active and b) without a cancellation + // the thread semaphore will be one count down. + // It is possible for this problem to affect other active objects. They symptom would be that finished signals + // from adopted threads are not sent, or they arrive much later than they should. + TRequestStatus *status = &iStatus; + User::RequestComplete(status, KErrNone); } } diff --git a/src/corelib/kernel/qeventdispatcher_symbian_p.h b/src/corelib/kernel/qeventdispatcher_symbian_p.h index e07d475..6e04bb1 100644 --- a/src/corelib/kernel/qeventdispatcher_symbian_p.h +++ b/src/corelib/kernel/qeventdispatcher_symbian_p.h @@ -110,6 +110,9 @@ public: protected: void DoCancel(); void RunL(); + +private: + TThreadId m_hostThreadId; }; struct SymbianTimerInfo : public QSharedData diff --git a/src/corelib/thread/qthread_symbian.cpp b/src/corelib/thread/qthread_symbian.cpp index 15e6898..5d8b5cb 100644 --- a/src/corelib/thread/qthread_symbian.cpp +++ b/src/corelib/thread/qthread_symbian.cpp @@ -113,6 +113,7 @@ QThreadData *QThreadData::current() } data->deref(); } + data->isAdopted = true; data->threadId = QThread::currentThreadId(); if (!QCoreApplicationPrivate::theMainThread) QCoreApplicationPrivate::theMainThread = data->thread; @@ -257,6 +258,13 @@ QCAddAdoptedThread* QCAddAdoptedThread::adoptedThreadAdder = 0; void QCAdoptedThreadMonitor::RunL() { + if (data->isAdopted) { + QThread *thread = data->thread; + Q_ASSERT(thread); + QThreadPrivate *thread_p = static_cast(QObjectPrivate::get(thread)); + Q_ASSERT(!thread_p->finished); + thread_p->finish(thread); + } data->deref(); QCAddAdoptedThread::threadDied(); delete this; -- cgit v0.12 From c7833b8f5ecc7a47e35bdf9fbb528e1869979ef5 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Thu, 7 Apr 2011 16:21:27 +1000 Subject: Fix TextEdit cursorRectangle property. Translate the cursor rectangle from control coordinates to painting coordinates rather than the other way around, ensure the cursor delegate is also translated, and update the cursor rectangle, cursor delegate and micro focus when the preedit cursor changes position. Change-Id: Iac7a87f7fb965d5f56d059d8f4b97feef8b47789 Task-number: QTBUG-18515 QT-4827 Reviewed-by: Martin Jones --- .../graphicsitems/qdeclarativetextedit.cpp | 15 ++++++--------- src/gui/text/qtextcontrol.cpp | 3 +++ .../qdeclarativetextedit/data/cursorTest.qml | 1 + .../tst_qdeclarativetextedit.cpp | 21 ++++++++++++++++++++- 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/declarative/graphicsitems/qdeclarativetextedit.cpp b/src/declarative/graphicsitems/qdeclarativetextedit.cpp index 2cb1c94..af2c8f3 100644 --- a/src/declarative/graphicsitems/qdeclarativetextedit.cpp +++ b/src/declarative/graphicsitems/qdeclarativetextedit.cpp @@ -582,6 +582,7 @@ void QDeclarativeTextEdit::setVAlign(QDeclarativeTextEdit::VAlignment alignment) d->vAlign = alignment; d->updateDefaultTextOption(); updateSize(); + moveCursorDelegate(); emit verticalAlignmentChanged(d->vAlign); } @@ -870,8 +871,6 @@ void QDeclarativeTextEdit::setCursorDelegate(QDeclarativeComponent* c) Q_D(QDeclarativeTextEdit); if(d->cursorComponent){ if(d->cursor){ - disconnect(d->control, SIGNAL(cursorPositionChanged()), - this, SLOT(moveCursorDelegate())); d->control->setCursorWidth(-1); dirtyCache(cursorRectangle()); delete d->cursor; @@ -897,8 +896,6 @@ void QDeclarativeTextEdit::loadCursorDelegate() return; d->cursor = qobject_cast(d->cursorComponent->create(qmlContext(this))); if(d->cursor){ - connect(d->control, SIGNAL(cursorPositionChanged()), - this, SLOT(moveCursorDelegate())); d->control->setCursorWidth(0); dirtyCache(cursorRectangle()); QDeclarative_setParent_noEvent(d->cursor, this); @@ -1173,7 +1170,7 @@ Qt::TextInteractionFlags QDeclarativeTextEdit::textInteractionFlags() const QRect QDeclarativeTextEdit::cursorRectangle() const { Q_D(const QDeclarativeTextEdit); - return d->control->cursorRect().toRect().translated(0,-d->yoff); + return d->control->cursorRect().toRect().translated(0,d->yoff); } @@ -1558,7 +1555,7 @@ void QDeclarativeTextEditPrivate::init() QObject::connect(control, SIGNAL(selectionChanged()), q, SLOT(updateSelectionMarkers())); QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SLOT(updateSelectionMarkers())); QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorPositionChanged())); - QObject::connect(control, SIGNAL(cursorPositionChanged()), q, SIGNAL(cursorRectangleChanged())); + QObject::connect(control, SIGNAL(microFocusChanged()), q, SLOT(moveCursorDelegate())); QObject::connect(control, SIGNAL(linkActivated(QString)), q, SIGNAL(linkActivated(QString))); #ifndef QT_NO_CLIPBOARD QObject::connect(q, SIGNAL(readOnlyChanged(bool)), q, SLOT(q_canPasteChanged())); @@ -1583,16 +1580,17 @@ void QDeclarativeTextEdit::q_textChanged() d->updateDefaultTextOption(); updateSize(); updateTotalLines(); - updateMicroFocus(); emit textChanged(d->text); } void QDeclarativeTextEdit::moveCursorDelegate() { Q_D(QDeclarativeTextEdit); + updateMicroFocus(); + emit cursorRectangleChanged(); if(!d->cursor) return; - QRectF cursorRect = d->control->cursorRect(); + QRectF cursorRect = cursorRectangle(); d->cursor->setX(cursorRect.x()); d->cursor->setY(cursorRect.y()); } @@ -1625,7 +1623,6 @@ void QDeclarativeTextEdit::updateSelectionMarkers() d->lastSelectionEnd = d->control->textCursor().selectionEnd(); emit selectionEndChanged(); } - updateMicroFocus(); } QRectF QDeclarativeTextEdit::boundingRect() const diff --git a/src/gui/text/qtextcontrol.cpp b/src/gui/text/qtextcontrol.cpp index 1a81394..bee4d95 100644 --- a/src/gui/text/qtextcontrol.cpp +++ b/src/gui/text/qtextcontrol.cpp @@ -1950,6 +1950,7 @@ void QTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) if (isGettingInput) layout->setPreeditArea(cursor.position() - block.position(), e->preeditString()); QList overrides; + const int oldPreeditCursor = preeditCursor; preeditCursor = e->preeditString().length(); hideCursor = false; for (int i = 0; i < e->attributes().size(); ++i) { @@ -1970,6 +1971,8 @@ void QTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) } layout->setAdditionalFormats(overrides); cursor.endEditBlock(); + if (oldPreeditCursor != preeditCursor) + emit q->microFocusChanged(); } QVariant QTextControl::inputMethodQuery(Qt::InputMethodQuery property) const diff --git a/tests/auto/declarative/qdeclarativetextedit/data/cursorTest.qml b/tests/auto/declarative/qdeclarativetextedit/data/cursorTest.qml index c7c21fc..f7fb3e7 100644 --- a/tests/auto/declarative/qdeclarativetextedit/data/cursorTest.qml +++ b/tests/auto/declarative/qdeclarativetextedit/data/cursorTest.qml @@ -2,6 +2,7 @@ import QtQuick 1.0 Rectangle { width: 300; height: 300; color: "white" TextEdit { text: "Hello world!"; id: textEditObject; objectName: "textEditObject" + anchors.fill: parent resources: [ Component { id:cursor; Item { id:cursorInstance; objectName: "cursorInstance" } } ] cursorDelegate: cursor } diff --git a/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp b/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp index 8f1be6f..574d2d5 100644 --- a/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp +++ b/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp @@ -1539,6 +1539,19 @@ void tst_qdeclarativetextedit::cursorDelegate() textEditObject->setCursorPosition(0); QCOMPARE(textEditObject->cursorRectangle().x(), qRound(delegateObject->x())); QCOMPARE(textEditObject->cursorRectangle().y(), qRound(delegateObject->y())); + QVERIFY(textEditObject->cursorRectangle().y() >= 0); + QVERIFY(textEditObject->cursorRectangle().y() < textEditObject->cursorRectangle().height()); + textEditObject->setVAlign(QDeclarativeTextEdit::AlignVCenter); + QCOMPARE(textEditObject->cursorRectangle().x(), qRound(delegateObject->x())); + QCOMPARE(textEditObject->cursorRectangle().y(), qRound(delegateObject->y())); + QVERIFY(textEditObject->cursorRectangle().y() > (textEditObject->height() / 2) - textEditObject->cursorRectangle().height()); + QVERIFY(textEditObject->cursorRectangle().y() < (textEditObject->height() / 2) + textEditObject->cursorRectangle().height()); + textEditObject->setVAlign(QDeclarativeTextEdit::AlignBottom); + QCOMPARE(textEditObject->cursorRectangle().x(), qRound(delegateObject->x())); + QCOMPARE(textEditObject->cursorRectangle().y(), qRound(delegateObject->y())); + QVERIFY(textEditObject->cursorRectangle().y() > textEditObject->height() - (textEditObject->cursorRectangle().height() * 2)); + QVERIFY(textEditObject->cursorRectangle().y() < textEditObject->height()); + //Test Delegate gets deleted textEditObject->setCursorDelegate(0); QVERIFY(!textEditObject->findChild("cursorInstance")); @@ -2227,6 +2240,8 @@ void tst_qdeclarativetextedit::preeditMicroFocus() QTest::qWaitForWindowShown(&view); QTRY_COMPARE(QApplication::activeWindow(), static_cast(&view)); + QSignalSpy cursorRectangleSpy(&edit, SIGNAL(cursorRectangleChanged())); + QRect currentRect; QRect previousRect = edit.inputMethodQuery(Qt::ImMicroFocus).toRect(); @@ -2237,8 +2252,9 @@ void tst_qdeclarativetextedit::preeditMicroFocus() currentRect = edit.inputMethodQuery(Qt::ImMicroFocus).toRect(); QCOMPARE(currentRect, previousRect); #if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN) - QCOMPARE(ic.updateReceived, true); + QCOMPARE(ic.updateReceived, false); // The cursor position hasn't changed. #endif + QCOMPARE(cursorRectangleSpy.count(), 0); // Verify that the micro focus rect moves to the left as the cursor position // is incremented. @@ -2250,6 +2266,8 @@ void tst_qdeclarativetextedit::preeditMicroFocus() #if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN) QCOMPARE(ic.updateReceived, true); #endif + QVERIFY(cursorRectangleSpy.count() > 0); + cursorRectangleSpy.clear(); previousRect = currentRect; } @@ -2263,6 +2281,7 @@ void tst_qdeclarativetextedit::preeditMicroFocus() #if defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN) QCOMPARE(ic.updateReceived, true); #endif + QVERIFY(cursorRectangleSpy.count() > 0); } void tst_qdeclarativetextedit::inputContextMouseHandler() -- cgit v0.12 From 1840a4383fd19bc64ef6d81c09c3f54aeb52d777 Mon Sep 17 00:00:00 2001 From: Sami Merila Date: Wed, 13 Apr 2011 11:34:46 +0300 Subject: Predictive Text causing app to crash after repeated edit attempts Splitview changes cause application to crash, since the cancellation of FEP transaction is not notified to the native side. This leads the native side and Qt to be not in sync. Task-number: QT-4879 Reviewed-by: Guoqing Zhang --- src/gui/inputmethod/qcoefepinputcontext_s60.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/inputmethod/qcoefepinputcontext_s60.cpp b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp index 868565d..8574f2c 100644 --- a/src/gui/inputmethod/qcoefepinputcontext_s60.cpp +++ b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp @@ -231,7 +231,7 @@ bool QCoeFepInputContext::filterEvent(const QEvent *event) // It ignores the mouse event, so we need to commit and send a selection event (which will get triggered // after the commit) if (!m_preeditString.isEmpty()) { - commitCurrentString(false); + commitCurrentString(true); int pos = focusWidget()->inputMethodQuery(Qt::ImCursorPosition).toInt(); -- cgit v0.12 From cc526edbff1cc413532f7ab1b6c088adae76744d Mon Sep 17 00:00:00 2001 From: Jani Hautakangas Date: Wed, 13 Apr 2011 11:38:13 +0300 Subject: Fix to 'QImage convertToFormat doesn't work correctly' OpenVG paint engine tries to use vgWritePixels shortcut whenever possible to optimize rendering performance. The check 'canVgWritePixels' failed to map formats correctly and resulted to incorrect return value. Task-number: QTBUG-18682 Reviewed-by: Jason Barron --- src/openvg/qpaintengine_vg.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/openvg/qpaintengine_vg.cpp b/src/openvg/qpaintengine_vg.cpp index 570adfd..ebdfa5f 100644 --- a/src/openvg/qpaintengine_vg.cpp +++ b/src/openvg/qpaintengine_vg.cpp @@ -1024,9 +1024,11 @@ static VGImage toVGImage switch (img.format()) { case QImage::Format_Mono: img = image.convertToFormat(QImage::Format_MonoLSB, flags); + img.invertPixels(); format = VG_BW_1; break; case QImage::Format_MonoLSB: + img.invertPixels(); format = VG_BW_1; break; case QImage::Format_RGB32: @@ -3189,6 +3191,19 @@ void qt_vg_drawVGImageStencil bool QVGPaintEngine::canVgWritePixels(const QImage &image) const { Q_D(const QVGPaintEngine); + + // qt_vg_image_to_vg_format returns VG_sARGB_8888 as + // fallback case if no matching VG format is found. + // If given image format is not Format_ARGB32 and returned + // format is VG_sARGB_8888, it means that no match was + // found. In that case vgWritePixels cannot be used. + // Also 1-bit formats cannot be used directly either. + if ((image.format() != QImage::Format_ARGB32 + && qt_vg_image_to_vg_format(image.format()) == VG_sARGB_8888) + || image.depth() == 1) { + return false; + } + // vgWritePixels ignores masking, blending and xforms so we can only use it if // ALL of the following conditions are true: // - It is a simple translate, or a scale of -1 on the y-axis (inverted) -- cgit v0.12 From 171c8b3dd904d3adf26d00ebaa0f372c1a8a5c71 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 22 Feb 2011 10:45:16 +0100 Subject: Autotest: Use the shadow-build trick in all platforms --- tests/auto/qsslkey/tst_qsslkey.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/auto/qsslkey/tst_qsslkey.cpp b/tests/auto/qsslkey/tst_qsslkey.cpp index e7b4740..86da09e 100644 --- a/tests/auto/qsslkey/tst_qsslkey.cpp +++ b/tests/auto/qsslkey/tst_qsslkey.cpp @@ -108,10 +108,8 @@ tst_QSslKey::tst_QSslKey() #ifdef Q_WS_MAC // applicationDirPath() points to a path inside the app bundle on Mac. QDir dir(qApp->applicationDirPath() + QLatin1String("/../../../keys")); -#elif defined(Q_OS_WIN) || defined (Q_OS_SYMBIAN) - QDir dir(SRCDIR + QLatin1String("/keys")); // prefer this way to avoid ifdeffery and support shadow builds? #else - QDir dir(qApp->applicationDirPath() + QLatin1String("/keys")); + QDir dir(SRCDIR + QLatin1String("/keys")); // prefer this way to avoid ifdeffery and support shadow builds? #endif QFileInfoList fileInfoList = dir.entryInfoList(QDir::Files | QDir::Readable); QRegExp rx(QLatin1String("^(rsa|dsa)-(pub|pri)-(\\d+)\\.(pem|der)$")); -- cgit v0.12 From 38d92bd2511ed56d7a7eece20a370e818fb8d05c Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 13 Apr 2011 14:33:55 +0200 Subject: Disable the JavaScriptCore JIT in ICC. As of ICC 12.0.2, ICC is known to miscompile some "fastcall" code, which causes runtime crashes. This fault has been reported to Intel and a fix is being prepared. Reviewed-by: Olivier Goffart --- configure | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/configure b/configure index 1369b82..30647c8 100755 --- a/configure +++ b/configure @@ -6750,8 +6750,15 @@ if [ "$CFG_JAVASCRIPTCORE_JIT" = "yes" ] || [ "$CFG_JAVASCRIPTCORE_JIT" = "auto" if [ $? != "0" ]; then CFG_JAVASCRIPTCORE_JIT=no fi - elif [ "$XPLATFORM" = "symbian-gcce" ]; then - CFG_JAVASCRIPTCORE_JIT=no + else + case "$XPLATFORM" in + symbian-gcce) + CFG_JAVASCRIPTCORE_JIT=no + ;; + linux-icc*) + CFG_JAVASCRIPTCORE_JIT=no + ;; + esac fi fi @@ -8585,7 +8592,7 @@ case "$CFG_WEBKIT" in debug) echo "WebKit module .......... yes (debug)" ;; no) echo "WebKit module .......... no" ;; esac -if [ "$CFG_WEBKIT" != "no" ]; then +if [ "$CFG_WEBKIT" != "no" ] || [ "$CFG_SCRIPT" != "no" ]; then if [ "$CFG_JAVASCRIPTCORE_JIT" = "auto" ]; then echo "JavaScriptCore JIT ..... To be decided by JavaScriptCore" else -- cgit v0.12 From 240ef633b827b33e2af63ff605eff5e1e71e623d Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 15 Feb 2011 09:49:34 +0100 Subject: Add the QDBusUnixFileDescriptor class This class holds one Unix file descriptor. It's implicitly shared, but it makes a copy of your file descriptor (via dup(2) or dup2(2)). This class is supposed to work even outside Unix systems, just that it will never do anything. Documentation in a later commit. Task-number: QTBUG-17477 --- src/dbus/dbus.pro | 6 +- src/dbus/qdbusunixfiledescriptor.cpp | 175 +++++++++++++++++++++++++++++++++++ src/dbus/qdbusunixfiledescriptor.h | 103 +++++++++++++++++++++ 3 files changed, 282 insertions(+), 2 deletions(-) create mode 100644 src/dbus/qdbusunixfiledescriptor.cpp create mode 100644 src/dbus/qdbusunixfiledescriptor.h diff --git a/src/dbus/dbus.pro b/src/dbus/dbus.pro index 52ed217..08c9ea1 100644 --- a/src/dbus/dbus.pro +++ b/src/dbus/dbus.pro @@ -59,7 +59,8 @@ HEADERS += $$PUB_HEADERS \ qdbusintegrator_p.h \ qdbuspendingcall_p.h \ qdbus_symbols_p.h \ - qdbusservicewatcher.h + qdbusservicewatcher.h \ + qdbusunixfiledescriptor.h SOURCES += qdbusconnection.cpp \ qdbusconnectioninterface.cpp \ qdbuserror.cpp \ @@ -85,4 +86,5 @@ SOURCES += qdbusconnection.cpp \ qdbuspendingcall.cpp \ qdbuspendingreply.cpp \ qdbus_symbols.cpp \ - qdbusservicewatcher.cpp + qdbusservicewatcher.cpp \ + qdbusunixfiledescriptor.cpp diff --git a/src/dbus/qdbusunixfiledescriptor.cpp b/src/dbus/qdbusunixfiledescriptor.cpp new file mode 100644 index 0000000..368753c --- /dev/null +++ b/src/dbus/qdbusunixfiledescriptor.cpp @@ -0,0 +1,175 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the FOO 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 "qdbusunixfiledescriptor.h" +#include + +#ifdef Q_OS_UNIX +# include +#endif + +class QDBusUnixFileDescriptorPrivate : public QSharedData { +public: + QDBusUnixFileDescriptorPrivate() : fd(-1) { } + QDBusUnixFileDescriptorPrivate(const QDBusUnixFileDescriptorPrivate &other) + : QSharedData(other), fd(-1) + { } + ~QDBusUnixFileDescriptorPrivate(); + + QAtomicInt fd; +}; + +template<> inline +QExplicitlySharedDataPointer::~QExplicitlySharedDataPointer() +{ if (d && !d->ref.deref()) delete d; } + +QDBusUnixFileDescriptor::QDBusUnixFileDescriptor() + : d(0) +{ +} + +QDBusUnixFileDescriptor::QDBusUnixFileDescriptor(int fileDescriptor) + : d(0) +{ + if (fileDescriptor != -1) + setFileDescriptor(fileDescriptor); +} + +QDBusUnixFileDescriptor::QDBusUnixFileDescriptor(const QDBusUnixFileDescriptor &other) + : d(other.d) +{ +} + +QDBusUnixFileDescriptor &QDBusUnixFileDescriptor::operator=(const QDBusUnixFileDescriptor &other) +{ + if (this != &other) + d.operator=(other.d); + return *this; +} + +QDBusUnixFileDescriptor::~QDBusUnixFileDescriptor() +{ +} + +bool QDBusUnixFileDescriptor::isValid() const +{ + return d ? d->fd != -1 : false; +} + +bool QDBusUnixFileDescriptor::isShared() const +{ + return d && d->ref == 1; +} + +int QDBusUnixFileDescriptor::fileDescriptor() const +{ + return d ? d->fd.operator int() : -1; +} + +// actual implementation +#ifdef Q_OS_UNIX + +bool QDBusUnixFileDescriptor::isSupported() +{ + return true; +} + +void QDBusUnixFileDescriptor::setFileDescriptor(int fileDescriptor) +{ + if (fileDescriptor != -1) + giveFileDescriptor(qt_safe_dup(fileDescriptor)); +} + +void QDBusUnixFileDescriptor::giveFileDescriptor(int fileDescriptor) +{ + // if we are the sole ref, d remains unchanged + // if detaching happens, d->fd will be -1 + if (d) + d.detach(); + else + d = new QDBusUnixFileDescriptorPrivate; + + if (d->fd != -1) + qt_safe_close(d->fd); + + if (fileDescriptor != -1) + d->fd = fileDescriptor; +} + +int QDBusUnixFileDescriptor::takeFileDescriptor() +{ + if (!d) + return -1; + + return d->fd.fetchAndStoreRelaxed(-1); +} + +QDBusUnixFileDescriptorPrivate::~QDBusUnixFileDescriptorPrivate() +{ + if (fd != -1) + qt_safe_close(fd); +} + +#else +bool QDBusUnixFileDescriptor::isSupported() +{ + return false; +} + +void QDBusUnixFileDescriptor::setFileDescriptor(int) +{ +} + +void QDBusUnixFileDescriptor::giveFileDescriptor(int) +{ +} + +int QDBusUnixFileDescriptor::takeFileDescriptor() +{ + return -1; +} + +QDBusUnixFileDescriptorPrivate::~QDBusUnixFileDescriptorPrivate() +{ +} + +#endif diff --git a/src/dbus/qdbusunixfiledescriptor.h b/src/dbus/qdbusunixfiledescriptor.h new file mode 100644 index 0000000..3ac3f9f --- /dev/null +++ b/src/dbus/qdbusunixfiledescriptor.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the FOO 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$ +** +****************************************************************************/ + + +#ifndef QDBUSUNIXFILEDESCRIPTOR_H +#define QDBUSUNIXFILEDESCRIPTOR_H + +#include +#include + +#ifndef QT_NO_DBUS + +#ifdef Q_COMPILER_RVALUE_REFS +# include +#endif + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(DBus) + +class QDBusUnixFileDescriptorPrivate; +template<> QExplicitlySharedDataPointer::~QExplicitlySharedDataPointer(); + +class Q_DBUS_EXPORT QDBusUnixFileDescriptor +{ +public: + QDBusUnixFileDescriptor(); + explicit QDBusUnixFileDescriptor(int fileDescriptor); + QDBusUnixFileDescriptor(const QDBusUnixFileDescriptor &other); + QDBusUnixFileDescriptor &operator=(const QDBusUnixFileDescriptor &other); + ~QDBusUnixFileDescriptor(); + + bool isValid() const; + bool isShared() const; + + int fileDescriptor() const; + void setFileDescriptor(int fileDescriptor); + + void giveFileDescriptor(int fileDescriptor); + int takeFileDescriptor(); + + static bool isSupported(); + +#if defined(Q_COMPILER_RVALUE_REFS) + QDBusUnixFileDescriptor(QDBusUnixFileDescriptor &&other) : d(static_cast(other.d)) + { } + inline QDBusUnixFileDescriptor &operator=(QDBusUnixFileDescriptor &&other) + { d.swap(other.d); return *this; } +#endif + +protected: + typedef QExplicitlySharedDataPointer Data; + Data d; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QDBusUnixFileDescriptor) + +QT_END_HEADER + +#endif // QT_NO_DBUS +#endif // QDBUSUNIXFILEDESCRIPTOR_H -- cgit v0.12 From 65c2711cadeaa0f543cf56d7172d37b90b15be27 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Tue, 15 Feb 2011 09:53:33 +0100 Subject: Add QDBusUnixFileDescriptor to the QtDBus metatype system Task-number: QTBUG-17477 --- src/dbus/qdbusmetatype.cpp | 15 ++++++++++++++- src/dbus/qdbusmetatype_p.h | 1 + src/dbus/qdbusutil.cpp | 5 +++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/dbus/qdbusmetatype.cpp b/src/dbus/qdbusmetatype.cpp index 9f29205..a361762 100644 --- a/src/dbus/qdbusmetatype.cpp +++ b/src/dbus/qdbusmetatype.cpp @@ -50,12 +50,18 @@ #include #include "qdbusmessage.h" +#include "qdbusunixfiledescriptor.h" #include "qdbusutil_p.h" #include "qdbusmetatype_p.h" #include "qdbusargument_p.h" #ifndef QT_NO_DBUS +#ifndef DBUS_TYPE_UNIX_FD +# define DBUS_TYPE_UNIX_FD int('h') +# define DBUS_TYPE_UNIX_FD_AS_STRING "h" +#endif + Q_DECLARE_METATYPE(QList) Q_DECLARE_METATYPE(QList) Q_DECLARE_METATYPE(QList) @@ -96,6 +102,7 @@ int QDBusMetaTypeId::variant; int QDBusMetaTypeId::objectpath; int QDBusMetaTypeId::signature; int QDBusMetaTypeId::error; +int QDBusMetaTypeId::unixfd; void QDBusMetaTypeId::init() { @@ -110,7 +117,8 @@ void QDBusMetaTypeId::init() variant = qRegisterMetaType("QDBusVariant"); objectpath = qRegisterMetaType("QDBusObjectPath"); signature = qRegisterMetaType("QDBusSignature"); - error = qRegisterMetaType("QDBusError"); + error = qRegisterMetaType("QDBusError"); + unixfd = qRegisterMetaType("QDBusUnixFileDescriptor"); #ifndef QDBUS_NO_SPECIALTYPES // and register QtCore's with us @@ -343,6 +351,9 @@ int QDBusMetaType::signatureToType(const char *signature) case DBUS_TYPE_SIGNATURE: return QDBusMetaTypeId::signature; + case DBUS_TYPE_UNIX_FD: + return QDBusMetaTypeId::unixfd; + case DBUS_TYPE_VARIANT: return QDBusMetaTypeId::variant; @@ -432,6 +443,8 @@ const char *QDBusMetaType::typeToSignature(int type) return DBUS_TYPE_OBJECT_PATH_AS_STRING; else if (type == QDBusMetaTypeId::signature) return DBUS_TYPE_SIGNATURE_AS_STRING; + else if (type == QDBusMetaTypeId::unixfd) + return DBUS_TYPE_UNIX_FD_AS_STRING; // try the database QVector *ct = customTypes(); diff --git a/src/dbus/qdbusmetatype_p.h b/src/dbus/qdbusmetatype_p.h index 2fce133..b931c75 100644 --- a/src/dbus/qdbusmetatype_p.h +++ b/src/dbus/qdbusmetatype_p.h @@ -65,6 +65,7 @@ struct QDBusMetaTypeId static int objectpath; // QDBusObjectPath static int signature; // QDBusSignature static int error; // QDBusError + static int unixfd; // QDBusUnixFileDescriptor static void init(); }; diff --git a/src/dbus/qdbusutil.cpp b/src/dbus/qdbusutil.cpp index 9730f54..844af9a 100644 --- a/src/dbus/qdbusutil.cpp +++ b/src/dbus/qdbusutil.cpp @@ -46,6 +46,7 @@ #include #include "qdbusargument.h" +#include "qdbusunixfiledescriptor.h" #ifndef QT_NO_DBUS @@ -130,6 +131,10 @@ static bool variantToString(const QVariant &arg, QString &out) } else if (argType == qMetaTypeId()) { out += QLatin1String("[Signature: ") + qvariant_cast(arg).signature(); out += QLatin1Char(']'); + } else if (argType == qMetaTypeId()) { + out += QLatin1String("[Unix FD: "); + out += QLatin1String(qvariant_cast(arg).isValid() ? "valid" : "not valid"); + out += QLatin1Char(']'); } else if (argType == qMetaTypeId()) { const QVariant v = qvariant_cast(arg).variant(); out += QLatin1String("[Variant"); -- cgit v0.12 From fe5822786526c69fc5566d480d4b37a5365db4e2 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 16 Feb 2011 12:14:03 +0100 Subject: Add support for D-Bus 1.4 features in QtDBus code Task-number: QTBUG-17477 --- src/dbus/qdbus_symbols_p.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/dbus/qdbus_symbols_p.h b/src/dbus/qdbus_symbols_p.h index c5f55af..d0a4b3e 100644 --- a/src/dbus/qdbus_symbols_p.h +++ b/src/dbus/qdbus_symbols_p.h @@ -296,6 +296,12 @@ DEFINEFUNC(dbus_bool_t , dbus_message_set_sender, (DBusMessage *message, DEFINEFUNC(void , dbus_message_unref, (DBusMessage *message), (message), ) +/* dbus-misc.h */ +DEFINEFUNC(void , dbus_get_version , (int *major_version_p, + int *minor_version_p, + int *micro_version_p), + (major_version_p, minor_version_p, micro_version_p), ) + /* dbus-pending-call.h */ DEFINEFUNC(dbus_bool_t , dbus_pending_call_set_notify, (DBusPendingCall *pending, DBusPendingCallNotifyFunction function, @@ -367,6 +373,14 @@ DEFINEFUNC(dbus_bool_t , dbus_type_is_fixed, (int typecode), /* dbus-thread.h */ DEFINEFUNC(dbus_bool_t , dbus_threads_init_default, (), (), return) + +/* D-Bus 1.4 symbols */ +#if !defined(QT_LINKED_LIBDBUS) || (DBUS_VERSION >= 0x010400) +DEFINEFUNC(dbus_bool_t , dbus_connection_can_send_type , (DBusConnection *connection, + int type), + (connection, type), return) +#endif + QT_END_NAMESPACE #endif // QT_NO_DBUS -- cgit v0.12 From 8334e79a0340c9fcd5ccedeb867a84044d4d83dd Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 16 Feb 2011 12:25:09 +0100 Subject: Retrieve the connection capabilities in QDBusConnection Task-number: QTBUG-17477 --- src/dbus/qdbusintegrator.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp index ee917a5..aaf19cf 100644 --- a/src/dbus/qdbusintegrator.cpp +++ b/src/dbus/qdbusintegrator.cpp @@ -1667,6 +1667,28 @@ void QDBusConnectionPrivate::setPeer(DBusConnection *c, const QDBusErrorInternal QMetaObject::invokeMethod(this, "doDispatch", Qt::QueuedConnection); } +static QDBusConnection::ConnectionCapabilities connectionCapabilies(DBusConnection *connection) +{ + QDBusConnection::ConnectionCapabilities result = 0; + +#if defined(QT_LINKED_LIBDBUS) && DBUS_VERSION < 0x010400 + // no capabilities are possible +#else +# if !defined(QT_LINKED_LIBDBUS) + // run-time check if the next functions are available + int major, minor, micro; + q_dbus_get_version(&major, &minor, µ); + if (major == 1 && minor < 4) + return result; +# endif + + if (q_dbus_connection_can_send_type(connection, DBUS_TYPE_UNIX_FD)) + result |= QDBusConnection::UnixFileDescriptorPassing; +#endif + + return result; +} + void QDBusConnectionPrivate::setConnection(DBusConnection *dbc, const QDBusErrorInternal &error) { if (!dbc) { @@ -1680,6 +1702,7 @@ void QDBusConnectionPrivate::setConnection(DBusConnection *dbc, const QDBusError const char *service = q_dbus_bus_get_unique_name(connection); Q_ASSERT(service); baseService = QString::fromUtf8(service); + capabilities = connectionCapabilies(connection); q_dbus_connection_set_exit_on_disconnect(connection, false); q_dbus_connection_set_watch_functions(connection, qDBusAddWatch, qDBusRemoveWatch, -- cgit v0.12 From 6d325d6f70c419d1fee49da1738633a3e03b46d4 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 16 Feb 2011 15:04:57 +0100 Subject: Add support for Unix file-descriptor passing to QtDBus Task-number: QTBUG-17477 --- src/dbus/qdbusargument.cpp | 28 ++++++++++++++++++++++++++ src/dbus/qdbusargument.h | 4 ++++ src/dbus/qdbusargument_p.h | 8 ++++++++ src/dbus/qdbusdemarshaller.cpp | 17 ++++++++++++++++ src/dbus/qdbusmarshaller.cpp | 20 +++++++++++++++++- src/dbus/qdbusmetatype.cpp | 1 + src/dbus/qdbusunixfiledescriptor.h | 1 + tests/auto/qdbusmarshall/common.h | 11 ++++++++++ tests/auto/qdbusmarshall/qdbusmarshall.pro | 2 ++ tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp | 23 +++++++++++++++++++++ 10 files changed, 114 insertions(+), 1 deletion(-) diff --git a/src/dbus/qdbusargument.cpp b/src/dbus/qdbusargument.cpp index 09f0e82..806b7fe 100644 --- a/src/dbus/qdbusargument.cpp +++ b/src/dbus/qdbusargument.cpp @@ -487,6 +487,20 @@ QDBusArgument &QDBusArgument::operator<<(const QDBusSignature &arg) /*! \overload + \since 4.8 + \internal + Appends the primitive value \a arg of type \c{UNIX_FILE_DESCRIPTOR} (Unix + File Descriptor) to the D-Bus stream. +*/ +QDBusArgument &QDBusArgument::operator<<(const QDBusUnixFileDescriptor &arg) +{ + if (QDBusArgumentPrivate::checkWrite(d)) + d->marshaller()->append(arg); + return *this; +} + +/*! + \overload Appends the primitive value \a arg of type \c{VARIANT} to the D-Bus stream. A D-Bus variant type can contain any type, including other @@ -729,6 +743,20 @@ const QDBusArgument &QDBusArgument::operator>>(QDBusSignature &arg) const /*! \overload + \since 4.8 + \internal + Extracts one D-Bus primitive argument of type \c{UNIX_FILE_DESCRIPTOR} + (Unix file descriptor) from the D-Bus stream. +*/ +const QDBusArgument &QDBusArgument::operator>>(QDBusUnixFileDescriptor &arg) const +{ + if (QDBusArgumentPrivate::checkReadAndDetach(d)) + arg = d->demarshaller()->toUnixFileDescriptor(); + return *this; +} + +/*! + \overload Extracts one D-Bus primitive argument of type \c{VARIANT} from the D-Bus stream. diff --git a/src/dbus/qdbusargument.h b/src/dbus/qdbusargument.h index e331d8f..f80723e 100644 --- a/src/dbus/qdbusargument.h +++ b/src/dbus/qdbusargument.h @@ -61,6 +61,8 @@ QT_BEGIN_NAMESPACE QT_MODULE(DBus) +class QDBusUnixFileDescriptor; + class QDBusArgumentPrivate; class QDBusDemarshaller; class QDBusMarshaller; @@ -96,6 +98,7 @@ public: QDBusArgument &operator<<(const QDBusVariant &arg); QDBusArgument &operator<<(const QDBusObjectPath &arg); QDBusArgument &operator<<(const QDBusSignature &arg); + QDBusArgument &operator<<(const QDBusUnixFileDescriptor &arg); QDBusArgument &operator<<(const QStringList &arg); QDBusArgument &operator<<(const QByteArray &arg); @@ -127,6 +130,7 @@ public: const QDBusArgument &operator>>(QDBusVariant &arg) const; const QDBusArgument &operator>>(QDBusObjectPath &arg) const; const QDBusArgument &operator>>(QDBusSignature &arg) const; + const QDBusArgument &operator>>(QDBusUnixFileDescriptor &arg) const; const QDBusArgument &operator>>(QStringList &arg) const; const QDBusArgument &operator>>(QByteArray &arg) const; diff --git a/src/dbus/qdbusargument_p.h b/src/dbus/qdbusargument_p.h index 89a383f..1c713a3 100644 --- a/src/dbus/qdbusargument_p.h +++ b/src/dbus/qdbusargument_p.h @@ -54,10 +54,16 @@ // #include +#include "qdbusunixfiledescriptor.h" #include "qdbus_symbols_p.h" #ifndef QT_NO_DBUS +#ifndef DBUS_TYPE_UNIX_FD +# define DBUS_TYPE_UNIX_FD int('h') +# define DBUS_TYPE_UNIX_FD_AS_STRING "h" +#endif + QT_BEGIN_NAMESPACE class QDBusMarshaller; @@ -117,6 +123,7 @@ public: void append(const QString &arg); void append(const QDBusObjectPath &arg); void append(const QDBusSignature &arg); + void append(const QDBusUnixFileDescriptor &arg); void append(const QStringList &arg); void append(const QByteArray &arg); bool append(const QDBusVariant &arg); // this one can fail @@ -172,6 +179,7 @@ public: QString toString(); QDBusObjectPath toObjectPath(); QDBusSignature toSignature(); + QDBusUnixFileDescriptor toUnixFileDescriptor(); QDBusVariant toVariant(); QStringList toStringList(); QByteArray toByteArray(); diff --git a/src/dbus/qdbusdemarshaller.cpp b/src/dbus/qdbusdemarshaller.cpp index 111122e..3910381 100644 --- a/src/dbus/qdbusdemarshaller.cpp +++ b/src/dbus/qdbusdemarshaller.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qdbusargument_p.h" +#include "qdbusconnection.h" #include QT_BEGIN_NAMESPACE @@ -126,6 +127,13 @@ inline QDBusSignature QDBusDemarshaller::toSignature() return QDBusSignature(QString::fromUtf8(qIterGet(&iterator))); } +inline QDBusUnixFileDescriptor QDBusDemarshaller::toUnixFileDescriptor() +{ + QDBusUnixFileDescriptor fd; + fd.giveFileDescriptor(qIterGet(&iterator)); + return fd; +} + inline QDBusVariant QDBusDemarshaller::toVariant() { QDBusDemarshaller sub(capabilities); @@ -173,6 +181,10 @@ QDBusArgument::ElementType QDBusDemarshaller::currentType() case DBUS_TYPE_DICT_ENTRY: return QDBusArgument::MapEntryType; + case DBUS_TYPE_UNIX_FD: + return capabilities & QDBusConnection::UnixFileDescriptorPassing ? + QDBusArgument::BasicType : QDBusArgument::UnknownType; + case DBUS_TYPE_INVALID: return QDBusArgument::UnknownType; @@ -231,6 +243,11 @@ QVariant QDBusDemarshaller::toVariantInternal() case DBUS_TYPE_STRUCT: return QVariant::fromValue(duplicate()); + case DBUS_TYPE_UNIX_FD: + if (capabilities & QDBusConnection::UnixFileDescriptorPassing) + return qVariantFromValue(toUnixFileDescriptor()); + // fall through + default: // qWarning("QDBusDemarshaller: Found unknown D-Bus type %d '%c'", // q_dbus_message_iter_get_arg_type(&iterator), diff --git a/src/dbus/qdbusmarshaller.cpp b/src/dbus/qdbusmarshaller.cpp index 76d76cc..edf743e 100644 --- a/src/dbus/qdbusmarshaller.cpp +++ b/src/dbus/qdbusmarshaller.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qdbusargument_p.h" +#include "qdbusconnection.h" #include "qdbusmetatype_p.h" #include "qdbusutil_p.h" @@ -138,6 +139,16 @@ inline void QDBusMarshaller::append(const QDBusSignature &arg) qIterAppend(&iterator, ba, DBUS_TYPE_SIGNATURE, &cdata); } +inline void QDBusMarshaller::append(const QDBusUnixFileDescriptor &arg) +{ + int fd = arg.fileDescriptor(); + if (!ba && fd == -1) { + error(QLatin1String("Invalid file descriptor passed in arguments")); + } else { + qIterAppend(&iterator, ba, DBUS_TYPE_UNIX_FD, &fd); + } +} + inline void QDBusMarshaller::append(const QByteArray &arg) { if (ba) { @@ -474,6 +485,13 @@ bool QDBusMarshaller::appendVariantInternal(const QVariant &arg) qFatal("QDBusMarshaller::appendVariantInternal got a DICT_ENTRY!"); return false; + case DBUS_TYPE_UNIX_FD: + if (capabilities & QDBusConnection::UnixFileDescriptorPassing || ba) { + append(qvariant_cast(arg)); + return true; + } + // fall through + default: qWarning("QDBusMarshaller::appendVariantInternal: Found unknown D-BUS type '%s'", signature); @@ -507,7 +525,7 @@ bool QDBusMarshaller::appendCrossMarshalling(QDBusDemarshaller *demarshaller) if (code == DBUS_TYPE_ARRAY) { int element = q_dbus_message_iter_get_element_type(&demarshaller->iterator); - if (q_dbus_type_is_fixed(element)) { + if (q_dbus_type_is_fixed(element) && element != DBUS_TYPE_UNIX_FD) { // another optimization: fixed size arrays // code is exactly like QDBusDemarshaller::toByteArray DBusMessageIter sub; diff --git a/src/dbus/qdbusmetatype.cpp b/src/dbus/qdbusmetatype.cpp index a361762..9d9112c 100644 --- a/src/dbus/qdbusmetatype.cpp +++ b/src/dbus/qdbusmetatype.cpp @@ -147,6 +147,7 @@ void QDBusMetaTypeId::init() qDBusRegisterMetaType >(); qDBusRegisterMetaType >(); qDBusRegisterMetaType >(); + qDBusRegisterMetaType >(); #endif initialized = true; diff --git a/src/dbus/qdbusunixfiledescriptor.h b/src/dbus/qdbusunixfiledescriptor.h index 3ac3f9f..92a770c 100644 --- a/src/dbus/qdbusunixfiledescriptor.h +++ b/src/dbus/qdbusunixfiledescriptor.h @@ -96,6 +96,7 @@ protected: QT_END_NAMESPACE Q_DECLARE_METATYPE(QDBusUnixFileDescriptor) +Q_DECLARE_METATYPE(QList) QT_END_HEADER diff --git a/tests/auto/qdbusmarshall/common.h b/tests/auto/qdbusmarshall/common.h index 532394a..b32b581 100644 --- a/tests/auto/qdbusmarshall/common.h +++ b/tests/auto/qdbusmarshall/common.h @@ -377,6 +377,14 @@ bool compare(const QHash &m1, const QHash &m2) return true; } +bool compare(const QDBusUnixFileDescriptor &t1, const QDBusUnixFileDescriptor &t2) +{ + int fd1 = t1.fileDescriptor(); + int fd2 = t2.fileDescriptor(); + + return (fd1 == -1) == (fd2 == -1); +} + template inline bool compare(const QDBusArgument &arg, const QVariant &v2, T * = 0) { @@ -563,6 +571,9 @@ template<> bool compare(const QVariant &v1, const QVariant &v2) else if (id == qMetaTypeId()) return qvariant_cast(v1).signature() == qvariant_cast(v2).signature(); + else if (id == qMetaTypeId()) + return compare(qvariant_cast(v1), qvariant_cast(v2)); + else if (id == qMetaTypeId()) return compare(qvariant_cast(v1).variant(), qvariant_cast(v2).variant()); diff --git a/tests/auto/qdbusmarshall/qdbusmarshall.pro b/tests/auto/qdbusmarshall/qdbusmarshall.pro index f8e0875..ad40c0d 100644 --- a/tests/auto/qdbusmarshall/qdbusmarshall.pro +++ b/tests/auto/qdbusmarshall/qdbusmarshall.pro @@ -3,6 +3,8 @@ contains(QT_CONFIG,dbus): { TEMPLATE = subdirs CONFIG += ordered SUBDIRS = qpong test + + requires(contains(QT_CONFIG,private_tests)) } else { SOURCES += dummy.cpp } diff --git a/tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp b/tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp index 9bae6af..828a807 100644 --- a/tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp +++ b/tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include "common.h" #include @@ -167,6 +168,9 @@ void tst_QDBusMarshall::sendBasic_data() QTest::newRow("signature") << qVariantFromValue(QDBusSignature("g")) << "g" << "[Signature: g]"; QTest::newRow("emptystring") << QVariant("") << "s" << "\"\""; QTest::newRow("nullstring") << QVariant(QString()) << "s" << "\"\""; + + if (QDBusConnection::sessionBus().connectionCapabilities() & QDBusConnection::UnixFileDescriptorPassing) + QTest::newRow("file-descriptor") << qVariantFromValue(QDBusUnixFileDescriptor(0)) << "h" << "[Unix FD: valid]"; #endif } @@ -967,6 +971,21 @@ typedef QScopedPointer ScopedDBusConnection; typedef QScopedPointer > ScopedDBusMessage; typedef QScopedPointer > ScopedDBusPendingCall; +template struct SetResetValue +{ + const T oldValue; + T &value; +public: + SetResetValue(T &v, T newValue) : oldValue(v), value(v) + { + value = newValue; + } + ~SetResetValue() + { + value = oldValue; + } +}; + void tst_QDBusMarshall::receiveUnknownType() { #ifndef DBUS_TYPE_UNIX_FD @@ -986,6 +1005,10 @@ void tst_QDBusMarshall::receiveUnknownType() if (!dbus_connection_can_send_type(rawcon.data(), DBUS_TYPE_UNIX_FD)) QSKIP("Your session bus does not allow sending Unix file descriptors", SkipAll); + // make sure this QDBusConnection won't handle Unix file descriptors + QDBusConnection::ConnectionCapabilities &capabRef = QDBusConnectionPrivate::d(con)->capabilities; + SetResetValue resetter(capabRef, capabRef & ~QDBusConnection::UnixFileDescriptorPassing); + if (qstrcmp(QTest::currentDataTag(), "in-call") == 0) { // create a call back to us containing a file descriptor QDBusMessageSpy spy; -- cgit v0.12 From 376239da147f7954f49e1c18dd53afcd57c3f771 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 16 Feb 2011 15:30:49 +0100 Subject: Autotest: Test QDBusUnixFileDescriptor support in arrays Task-number: QTBUG-17477 --- tests/auto/qdbusmarshall/common.h | 2 ++ tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/tests/auto/qdbusmarshall/common.h b/tests/auto/qdbusmarshall/common.h index b32b581..dfa5206 100644 --- a/tests/auto/qdbusmarshall/common.h +++ b/tests/auto/qdbusmarshall/common.h @@ -475,6 +475,8 @@ bool compareToArgument(const QDBusArgument &arg, const QVariant &v2) return compare >(arg, v2); else if (id == qMetaTypeId >()) return compare >(arg, v2); + else if (id == qMetaTypeId >()) + return compare >(arg, v2); else if (id == qMetaTypeId >()) return compare >(arg, v2); diff --git a/tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp b/tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp index 828a807..df31ca2 100644 --- a/tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp +++ b/tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp @@ -95,6 +95,7 @@ private slots: private: QProcess proc; + bool fileDescriptorPassing; }; class QDBusMessageSpy: public QObject @@ -117,6 +118,7 @@ void tst_QDBusMarshall::initTestCase() { commonInit(); QDBusConnection con = QDBusConnection::sessionBus(); + fileDescriptorPassing = con.connectionCapabilities() & QDBusConnection::UnixFileDescriptorPassing; #ifdef Q_OS_WIN proc.start("qpong"); #else @@ -169,7 +171,7 @@ void tst_QDBusMarshall::sendBasic_data() QTest::newRow("emptystring") << QVariant("") << "s" << "\"\""; QTest::newRow("nullstring") << QVariant(QString()) << "s" << "\"\""; - if (QDBusConnection::sessionBus().connectionCapabilities() & QDBusConnection::UnixFileDescriptorPassing) + if (fileDescriptorPassing) QTest::newRow("file-descriptor") << qVariantFromValue(QDBusUnixFileDescriptor(0)) << "h" << "[Unix FD: valid]"; #endif } @@ -259,6 +261,18 @@ void tst_QDBusMarshall::sendArrays_data() << std::numeric_limits::quiet_NaN(); QTest::newRow("doublelist") << qVariantFromValue(doubles) << "ad" << "[Argument: ad {1.2, 2.2, 4.4, -inf, inf, nan}]"; + QList objectPaths; + QTest::newRow("emptyobjectpathlist") << qVariantFromValue(objectPaths) << "ao" << "[Argument: ao {}]"; + objectPaths << QDBusObjectPath("/") << QDBusObjectPath("/foo"); + QTest::newRow("objectpathlist") << qVariantFromValue(objectPaths) << "ao" << "[Argument: ao {[ObjectPath: /], [ObjectPath: /foo]}]"; + + if (fileDescriptorPassing) { + QList fileDescriptors; + QTest::newRow("emptyfiledescriptorlist") << qVariantFromValue(fileDescriptors) << "ah" << "[Argument: ah {}]"; + fileDescriptors << QDBusUnixFileDescriptor(0) << QDBusUnixFileDescriptor(1); + QTest::newRow("filedescriptorlist") << qVariantFromValue(fileDescriptors) << "ah" << "[Argument: ah {[Unix FD: valid], [Unix FD: valid]}]"; + } + QVariantList variants; QTest::newRow("emptyvariantlist") << QVariant(variants) << "av" << "[Argument: av {}]"; variants << QString("Hello") << QByteArray("World") << 42 << -43.0 << 44U << Q_INT64_C(-45) -- cgit v0.12 From f60b8f84332fcf5cb8be94ba8143595285baf134 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 16 Feb 2011 16:57:10 +0100 Subject: Autotest: more file-descriptor passing tests Task-number: QTBUG-17477 --- tests/auto/qdbusmarshall/common.h | 48 +++++++++++++++++++++----- tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp | 45 ++++++++++++++++++++++++ 2 files changed, 85 insertions(+), 8 deletions(-) diff --git a/tests/auto/qdbusmarshall/common.h b/tests/auto/qdbusmarshall/common.h index dfa5206..53bd0e5 100644 --- a/tests/auto/qdbusmarshall/common.h +++ b/tests/auto/qdbusmarshall/common.h @@ -77,6 +77,14 @@ Q_DECLARE_METATYPE(ObjectPathStringMap) Q_DECLARE_METATYPE(LLDateTimeMap) Q_DECLARE_METATYPE(SignatureStringMap) +static bool compare(const QDBusUnixFileDescriptor &t1, const QDBusUnixFileDescriptor &t2) +{ + int fd1 = t1.fileDescriptor(); + int fd2 = t2.fileDescriptor(); + + return (fd1 == -1) == (fd2 == -1); +} + struct MyStruct { int i; @@ -130,6 +138,32 @@ const QDBusArgument &operator>>(const QDBusArgument &arg, MyVariantMapStruct &ms return arg; } +struct MyFileDescriptorStruct +{ + QDBusUnixFileDescriptor fd; + + inline bool operator==(const MyFileDescriptorStruct &other) const + { return compare(fd, other.fd); } +}; +Q_DECLARE_METATYPE(MyFileDescriptorStruct) +Q_DECLARE_METATYPE(QList) + +QDBusArgument &operator<<(QDBusArgument &arg, const MyFileDescriptorStruct &ms) +{ + arg.beginStructure(); + arg << ms.fd; + arg.endStructure(); + return arg; +} + +const QDBusArgument &operator>>(const QDBusArgument &arg, MyFileDescriptorStruct &ms) +{ + arg.beginStructure(); + arg >> ms.fd; + arg.endStructure(); + return arg; +} + void commonInit() { @@ -157,6 +191,8 @@ void commonInit() qDBusRegisterMetaType(); qDBusRegisterMetaType(); qDBusRegisterMetaType >(); + qDBusRegisterMetaType(); + qDBusRegisterMetaType >(); } #ifdef USE_PRIVATE_CODE #include "private/qdbusintrospection_p.h" @@ -377,14 +413,6 @@ bool compare(const QHash &m1, const QHash &m2) return true; } -bool compare(const QDBusUnixFileDescriptor &t1, const QDBusUnixFileDescriptor &t2) -{ - int fd1 = t1.fileDescriptor(); - int fd2 = t2.fileDescriptor(); - - return (fd1 == -1) == (fd2 == -1); -} - template inline bool compare(const QDBusArgument &arg, const QVariant &v2, T * = 0) { @@ -521,6 +549,10 @@ bool compareToArgument(const QDBusArgument &arg, const QVariant &v2) return compare(arg, v2); else if (id == qMetaTypeId >()) return compare >(arg, v2); + else if (id == qMetaTypeId()) + return compare(arg, v2); + else if (id == qMetaTypeId >()) + return compare >(arg, v2); } qWarning() << "Unexpected QVariant type" << v2.userType() diff --git a/tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp b/tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp index df31ca2..b7cec3e 100644 --- a/tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp +++ b/tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp @@ -474,6 +474,12 @@ void tst_QDBusMarshall::sendMaps_data() QTest::newRow("gs-map") << qVariantFromValue(gsmap) << "a{gs}" << "[Argument: a{gs} {[Signature: a{gs}] = \"array of dict_entry of (signature, string)\", [Signature: i] = \"int32\", [Signature: s] = \"string\"}]"; + if (fileDescriptorPassing) { + svmap["zzfiledescriptor"] = qVariantFromValue(QDBusUnixFileDescriptor(0)); + QTest::newRow("sv-map1-fd") << qVariantFromValue(svmap) << "a{sv}" + << "[Argument: a{sv} {\"a\" = [Variant(int): 1], \"b\" = [Variant(QByteArray): {99}], \"c\" = [Variant(QString): \"b\"], \"d\" = [Variant(uint): 42], \"e\" = [Variant(short): -47], \"f\" = [Variant: [Variant(int): 0]], \"zzfiledescriptor\" = [Variant(QDBusUnixFileDescriptor): [Unix FD: valid]]}]"; + } + svmap.clear(); svmap["ismap"] = qVariantFromValue(ismap); svmap["ssmap"] = qVariantFromValue(ssmap); @@ -527,6 +533,18 @@ void tst_QDBusMarshall::sendStructs_data() QTest::newRow("empty-list-of-string-variantmap") << qVariantFromValue(list) << "a(sa{sv})" << "[Argument: a(sa{sv}) {}]"; list << mvms; QTest::newRow("list-of-string-variantmap") << qVariantFromValue(list) << "a(sa{sv})" << "[Argument: a(sa{sv}) {[Argument: (sa{sv}) \"Hello, World\", [Argument: a{sv} {\"bytearray\" = [Variant(QByteArray): {72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100}], \"int\" = [Variant(int): 42], \"short\" = [Variant(short): -47], \"uint\" = [Variant(uint): 42]}]]}]"; + + if (fileDescriptorPassing) { + MyFileDescriptorStruct fds; + fds.fd = QDBusUnixFileDescriptor(0); + QTest::newRow("fdstruct") << qVariantFromValue(fds) << "(h)" << "[Argument: (h) [Unix FD: valid]]"; + + QList fdlist; + QTest::newRow("empty-list-of-fdstruct") << qVariantFromValue(fdlist) << "a(h)" << "[Argument: a(h) {}]"; + + fdlist << fds; + QTest::newRow("list-of-fdstruct") << qVariantFromValue(fdlist) << "a(h)" << "[Argument: a(h) {[Argument: (h) [Unix FD: valid]]}]"; + } } void tst_QDBusMarshall::sendComplex_data() @@ -660,6 +678,12 @@ void tst_QDBusMarshall::sendArgument_data() arg << QString(); QTest::newRow("nullstring") << qVariantFromValue(arg) << "s" << int(QDBusArgument::BasicType); + if (fileDescriptorPassing) { + arg = QDBusArgument(); + arg << QDBusUnixFileDescriptor(0); + QTest::newRow("filedescriptor") << qVariantFromValue(arg) << "h" << int(QDBusArgument::BasicType); + } + arg = QDBusArgument(); arg << QDBusVariant(1); QTest::newRow("variant") << qVariantFromValue(arg) << "v" << int(QDBusArgument::VariantType); @@ -920,6 +944,27 @@ void tst_QDBusMarshall::sendCallErrors_data() << "Marshalling failed: Unregistered type UnregisteredType passed in arguments" << QString("QDBusMarshaller: type `UnregisteredType' (%1) is not registered with D-BUS. Use qDBusRegisterMetaType to register it") .arg(qMetaTypeId()); + + QTest::newRow("invalid-object-path-arg") << serviceName << objectPath << interfaceName << "ping" + << (QVariantList() << qVariantFromValue(QDBusObjectPath())) + << "org.freedesktop.DBus.Error.Failed" + << "Marshalling failed: Invalid object path passed in arguments" + << ""; + + QTest::newRow("invalid-signature-arg") << serviceName << objectPath << interfaceName << "ping" + << (QVariantList() << qVariantFromValue(QDBusSignature())) + << "org.freedesktop.DBus.Error.Failed" + << "Marshalling failed: Invalid signature passed in arguments" + << ""; + + // invalid file descriptor + if (fileDescriptorPassing) { + QTest::newRow("invalid-file-descriptor") << serviceName << objectPath << interfaceName << "ping" + << (QVariantList() << qVariantFromValue(QDBusUnixFileDescriptor(-1))) + << "org.freedesktop.DBus.Error.Failed" + << "Marshalling failed: Invalid file descriptor passed in arguments" + << ""; + } } void tst_QDBusMarshall::sendCallErrors() -- cgit v0.12 From 7647521500b0d1c1e382fff0d1a0f497f1fac70c Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 17 Feb 2011 17:01:14 +0100 Subject: Autotest: really ensure that two fds are equal Instead of checking that they are both valid or both invalid, test that they point to the same file on the filesystem. So we create a QTemporaryFile and pass its file descriptor to the remote side and back. If the two fds point to the same file on disk later (same st_dev and st_ino), they are equal. This probably works on non-Unix too, but I can't test and there's no point anyway. Task-number: QTBUG-17477 --- tests/auto/qdbusmarshall/common.h | 26 +++++++++++++++++++++++++- tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp | 22 +++++++++++++++++----- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/tests/auto/qdbusmarshall/common.h b/tests/auto/qdbusmarshall/common.h index 53bd0e5..8f7f3c3 100644 --- a/tests/auto/qdbusmarshall/common.h +++ b/tests/auto/qdbusmarshall/common.h @@ -39,6 +39,22 @@ ** ****************************************************************************/ #include // isnan +#include + +#ifdef Q_OS_UNIX +# include + +static bool compareFileDescriptors(int fd1, int fd2) +{ + QT_STATBUF st1, st2; + if (QT_FSTAT(fd1, &st1) == -1 || QT_FSTAT(fd2, &st2) == -1) { + perror("fstat"); + return false; + } + + return (st1.st_dev == st2.st_dev) && (st1.st_ino == st2.st_ino); +} +#endif Q_DECLARE_METATYPE(QVariant) Q_DECLARE_METATYPE(QList) @@ -81,8 +97,16 @@ static bool compare(const QDBusUnixFileDescriptor &t1, const QDBusUnixFileDescri { int fd1 = t1.fileDescriptor(); int fd2 = t2.fileDescriptor(); + if ((fd1 == -1 || fd2 == -1) && fd1 != fd2) { + // one is valid, the other isn't + return false; + } - return (fd1 == -1) == (fd2 == -1); +#ifdef Q_OS_UNIX + return compareFileDescriptors(fd1, fd2); +#else + return true; +#endif } struct MyStruct diff --git a/tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp b/tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp index b7cec3e..737f0cf 100644 --- a/tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp +++ b/tests/auto/qdbusmarshall/tst_qdbusmarshall.cpp @@ -94,7 +94,10 @@ private slots: void receiveUnknownType(); private: + int fileDescriptorForTest(); + QProcess proc; + QTemporaryFile tempFile; bool fileDescriptorPassing; }; @@ -147,6 +150,15 @@ void tst_QDBusMarshall::cleanupTestCase() proc.waitForFinished(200); } +int tst_QDBusMarshall::fileDescriptorForTest() +{ + if (!tempFile.isOpen()) { + tempFile.setFileTemplate(QDir::tempPath() + "/qdbusmarshalltestXXXXXX.tmp"); + tempFile.open(); + } + return tempFile.handle(); +} + void tst_QDBusMarshall::sendBasic_data() { QTest::addColumn("value"); @@ -172,7 +184,7 @@ void tst_QDBusMarshall::sendBasic_data() QTest::newRow("nullstring") << QVariant(QString()) << "s" << "\"\""; if (fileDescriptorPassing) - QTest::newRow("file-descriptor") << qVariantFromValue(QDBusUnixFileDescriptor(0)) << "h" << "[Unix FD: valid]"; + QTest::newRow("file-descriptor") << qVariantFromValue(QDBusUnixFileDescriptor(fileDescriptorForTest())) << "h" << "[Unix FD: valid]"; #endif } @@ -269,7 +281,7 @@ void tst_QDBusMarshall::sendArrays_data() if (fileDescriptorPassing) { QList fileDescriptors; QTest::newRow("emptyfiledescriptorlist") << qVariantFromValue(fileDescriptors) << "ah" << "[Argument: ah {}]"; - fileDescriptors << QDBusUnixFileDescriptor(0) << QDBusUnixFileDescriptor(1); + fileDescriptors << QDBusUnixFileDescriptor(fileDescriptorForTest()) << QDBusUnixFileDescriptor(1); QTest::newRow("filedescriptorlist") << qVariantFromValue(fileDescriptors) << "ah" << "[Argument: ah {[Unix FD: valid], [Unix FD: valid]}]"; } @@ -475,7 +487,7 @@ void tst_QDBusMarshall::sendMaps_data() << "[Argument: a{gs} {[Signature: a{gs}] = \"array of dict_entry of (signature, string)\", [Signature: i] = \"int32\", [Signature: s] = \"string\"}]"; if (fileDescriptorPassing) { - svmap["zzfiledescriptor"] = qVariantFromValue(QDBusUnixFileDescriptor(0)); + svmap["zzfiledescriptor"] = qVariantFromValue(QDBusUnixFileDescriptor(fileDescriptorForTest())); QTest::newRow("sv-map1-fd") << qVariantFromValue(svmap) << "a{sv}" << "[Argument: a{sv} {\"a\" = [Variant(int): 1], \"b\" = [Variant(QByteArray): {99}], \"c\" = [Variant(QString): \"b\"], \"d\" = [Variant(uint): 42], \"e\" = [Variant(short): -47], \"f\" = [Variant: [Variant(int): 0]], \"zzfiledescriptor\" = [Variant(QDBusUnixFileDescriptor): [Unix FD: valid]]}]"; } @@ -536,7 +548,7 @@ void tst_QDBusMarshall::sendStructs_data() if (fileDescriptorPassing) { MyFileDescriptorStruct fds; - fds.fd = QDBusUnixFileDescriptor(0); + fds.fd = QDBusUnixFileDescriptor(fileDescriptorForTest()); QTest::newRow("fdstruct") << qVariantFromValue(fds) << "(h)" << "[Argument: (h) [Unix FD: valid]]"; QList fdlist; @@ -680,7 +692,7 @@ void tst_QDBusMarshall::sendArgument_data() if (fileDescriptorPassing) { arg = QDBusArgument(); - arg << QDBusUnixFileDescriptor(0); + arg << QDBusUnixFileDescriptor(fileDescriptorForTest()); QTest::newRow("filedescriptor") << qVariantFromValue(arg) << "h" << int(QDBusArgument::BasicType); } -- cgit v0.12 From 0c8fa16ef1964c3d102413b44e18964f6b4793ec Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 13 Apr 2011 14:50:03 +0200 Subject: Doc: document the QDBusUnixFileDescriptor class --- src/dbus/qdbusunixfiledescriptor.cpp | 145 +++++++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) diff --git a/src/dbus/qdbusunixfiledescriptor.cpp b/src/dbus/qdbusunixfiledescriptor.cpp index 368753c..9cbaa8f 100644 --- a/src/dbus/qdbusunixfiledescriptor.cpp +++ b/src/dbus/qdbusunixfiledescriptor.cpp @@ -47,6 +47,59 @@ # include #endif +/*! + \class QDBusUnixFileDescriptor + \inmodule QtDBus + \since 4.8 + + \brief The QDBusUnixFileDescriptor class holds one Unix file descriptor. + + The QDBusUnixFileDescriptor class is used to hold one Unix file + descriptor for use with the QtDBus module. This allows applications to + send and receive Unix file descriptors over the D-Bus connection, mapping + automatically to the D-Bus type 'h'. + + Objects of type QDBusUnixFileDescriptors can be used also as parameters + in signals and slots that get exported to D-Bus by registering with + QDBusConnection::registerObject. + + QDBusUnixFileDescriptor does not take ownership of the file descriptor. + Instead, it will use the Unix system call \c dup(2) to make a copy of the + file descriptor. This file descriptor belongs to the + QDBusUnixFileDescriptor object and should not be stored or closed by the + user. Instead, you should make your own copy if you need that. + + \section2 Availability + + Unix file descriptor passing is not available in all D-Bus connections. + This feature is present with D-Bus library and bus daemon version 1.4 and + upwards on Unix systems. QtDBus automatically enables the feature if such + a version was found at compile-time and run-time. + + To verify that your connection does support passing file descriptors, + check if the QDBusConnection::UnixFileDescriptorPassing capability is set + with QDBusConnection::connectionCapabilities(). If the flag is not + active, then you will not be able to make calls to methods that have + QDBusUnixFileDescriptor as arguments or even embed such a type in a + variant. You will also not receive calls containing that type. + + Note also that remote applications may not have support for Unix file + descriptor passing. If you make a D-Bus to a remote application that + cannot receive such a type, you will receive an error reply. If you try + to send a signal containing a D-Bus file descriptor or return one from a + method call, the message will be silently dropped. + + Even if the feature is not available, QDBusUnixFileDescriptor will + continue to operate, so code need not have compile-time checks for the + availability of this feature. + + On non-Unix systems, QDBusUnixFileDescriptor will always report an + invalid state and QDBusUnixFileDescriptor::isSupported() will return + false. + + \sa QDBusConnection::ConnectionCapabilities, QDBusConnection::connectionCapabilities +*/ + class QDBusUnixFileDescriptorPrivate : public QSharedData { public: QDBusUnixFileDescriptorPrivate() : fd(-1) { } @@ -62,11 +115,31 @@ template<> inline QExplicitlySharedDataPointer::~QExplicitlySharedDataPointer() { if (d && !d->ref.deref()) delete d; } +/*! + Constructs a QDBusUnixFileDescriptor without a wrapped file descriptor. + This is equivalent to constructing the object with an invalid file + descriptor (like -1). + + \sa fileDescriptor, isValid +*/ QDBusUnixFileDescriptor::QDBusUnixFileDescriptor() : d(0) { } +/*! + Constructs a QDBusUnixFileDescriptor object by copying the \a + fileDescriptor parameter. The original file descriptor is not touched and + must be closed by the user. + + Note that the value returned by fileDescriptor() will be different from + the \a fileDescriptor parameter passed. + + If the \a fileDescriptor parameter is not valid, isValid() will return + false and fileDescriptor() will return -1. + + \sa setFileDescriptor, fileDescriptor +*/ QDBusUnixFileDescriptor::QDBusUnixFileDescriptor(int fileDescriptor) : d(0) { @@ -74,11 +147,19 @@ QDBusUnixFileDescriptor::QDBusUnixFileDescriptor(int fileDescriptor) setFileDescriptor(fileDescriptor); } +/*! + Constructs a QDBusUnixFileDescriptor object by copying \a other. +*/ QDBusUnixFileDescriptor::QDBusUnixFileDescriptor(const QDBusUnixFileDescriptor &other) : d(other.d) { } +/*! + Copies the Unix file descriptor from the \a other QDBusUnixFileDescriptor + object. If the current object contained a file descriptor, it will be + properly disposed of before. +*/ QDBusUnixFileDescriptor &QDBusUnixFileDescriptor::operator=(const QDBusUnixFileDescriptor &other) { if (this != &other) @@ -86,20 +167,45 @@ QDBusUnixFileDescriptor &QDBusUnixFileDescriptor::operator=(const QDBusUnixFileD return *this; } +/*! + Destroys this QDBusUnixFileDescriptor object and disposes of the Unix file descriptor that it contained. +*/ QDBusUnixFileDescriptor::~QDBusUnixFileDescriptor() { } +/*! + Returns true if this Unix file descriptor is valid. A valid Unix file + descriptor is not -1. + + \sa fileDescriptor() +*/ bool QDBusUnixFileDescriptor::isValid() const { return d ? d->fd != -1 : false; } +/*! + \internal +*/ bool QDBusUnixFileDescriptor::isShared() const { return d && d->ref == 1; } +/*! + Returns the Unix file descriptor contained by this + QDBusUnixFileDescriptor object. An invalid file descriptor is represented + by the value -1. + + Note that the file descriptor returned by this function is owned by the + QDBusUnixFileDescriptor object and must not be stored past the lifetime + of this object. It is ok to use it while this object is valid, but if one + wants to store it for longer use, the file descriptor should be cloned + using the Unix \c dup(2), \c dup2(2) or \c dup3(2) functions. + + \sa isValid() +*/ int QDBusUnixFileDescriptor::fileDescriptor() const { return d ? d->fd.operator int() : -1; @@ -108,17 +214,48 @@ int QDBusUnixFileDescriptor::fileDescriptor() const // actual implementation #ifdef Q_OS_UNIX +// qdoc documentation is generated on Unix + +/*! + Returns true if Unix file descriptors are supported on this platform. In + other words, this function returns true if this is a Unix platform. + + Note that QDBusUnixFileDescriptor continues to operate even if this + function returns false. The only difference is that the + QDBusUnixFileDescriptor objects will always be in the isValid() == false + state and fileDescriptor() will always return -1. The class will not + consume any operating system resources. +*/ bool QDBusUnixFileDescriptor::isSupported() { return true; } +/*! + Sets the file descriptor that this QDBusUnixFileDescriptor object holds + to a copy of \a fileDescriptor.T he original file descriptor is not + touched and must be closed by the user. + + Note that the value returned by fileDescriptor() will be different from + the \a fileDescriptor parameter passed. + + If the \a fileDescriptor parameter is not valid, isValid() will return + false and fileDescriptor() will return -1. + + \sa isValid(), fileDescriptor() +*/ void QDBusUnixFileDescriptor::setFileDescriptor(int fileDescriptor) { if (fileDescriptor != -1) giveFileDescriptor(qt_safe_dup(fileDescriptor)); } +/*! + \internal + Sets the Unix file descriptor to \a fileDescriptor without copying. + + \sa setFileDescriptor() +*/ void QDBusUnixFileDescriptor::giveFileDescriptor(int fileDescriptor) { // if we are the sole ref, d remains unchanged @@ -135,6 +272,14 @@ void QDBusUnixFileDescriptor::giveFileDescriptor(int fileDescriptor) d->fd = fileDescriptor; } +/*! + \internal + Extracts the Unix file descriptor from the QDBusUnixFileDescriptor object + and transfers ownership. + + Note: since QDBusUnixFileDescriptor is implicitly shared, this function + is inherently racy and should be avoided. +*/ int QDBusUnixFileDescriptor::takeFileDescriptor() { if (!d) -- cgit v0.12 From 0ee167c7d47c28d747e9ca73aa35fef21171b97f Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 13 Apr 2011 14:52:49 +0200 Subject: Remove the unused QDBusUnixFileDescriptor::isShared function --- src/dbus/qdbusunixfiledescriptor.cpp | 8 -------- src/dbus/qdbusunixfiledescriptor.h | 1 - 2 files changed, 9 deletions(-) diff --git a/src/dbus/qdbusunixfiledescriptor.cpp b/src/dbus/qdbusunixfiledescriptor.cpp index 9cbaa8f..4817d95 100644 --- a/src/dbus/qdbusunixfiledescriptor.cpp +++ b/src/dbus/qdbusunixfiledescriptor.cpp @@ -186,14 +186,6 @@ bool QDBusUnixFileDescriptor::isValid() const } /*! - \internal -*/ -bool QDBusUnixFileDescriptor::isShared() const -{ - return d && d->ref == 1; -} - -/*! Returns the Unix file descriptor contained by this QDBusUnixFileDescriptor object. An invalid file descriptor is represented by the value -1. diff --git a/src/dbus/qdbusunixfiledescriptor.h b/src/dbus/qdbusunixfiledescriptor.h index 92a770c..d0a2f3c 100644 --- a/src/dbus/qdbusunixfiledescriptor.h +++ b/src/dbus/qdbusunixfiledescriptor.h @@ -71,7 +71,6 @@ public: ~QDBusUnixFileDescriptor(); bool isValid() const; - bool isShared() const; int fileDescriptor() const; void setFileDescriptor(int fileDescriptor); -- cgit v0.12 From b53a80ff1e1a1a5e8c66eaa20076be2745ffb88f Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 21 Feb 2011 20:01:03 +0100 Subject: Add routines to validate D-Bus signature in QtDBus --- src/dbus/qdbusutil.cpp | 95 +++++++++++- src/dbus/qdbusutil_p.h | 4 + tests/auto/dbus.pro | 1 + tests/auto/qdbustype/qdbustype.pro | 10 ++ tests/auto/qdbustype/tst_qdbustype.cpp | 271 +++++++++++++++++++++++++++++++++ 5 files changed, 379 insertions(+), 2 deletions(-) create mode 100644 tests/auto/qdbustype/qdbustype.pro create mode 100644 tests/auto/qdbustype/tst_qdbustype.cpp diff --git a/src/dbus/qdbusutil.cpp b/src/dbus/qdbusutil.cpp index 844af9a..a4bd168 100644 --- a/src/dbus/qdbusutil.cpp +++ b/src/dbus/qdbusutil.cpp @@ -238,6 +238,68 @@ bool argToString(const QDBusArgument &busArg, QString &out) return true; } +//------- D-Bus Types -------- +static const char oneLetterTypes[] = "vsogybnqiuxtdh"; +static const char basicTypes[] = "sogybnqiuxtdh"; +static const char fixedTypes[] = "ybnqiuxtdh"; + +static bool isBasicType(int c) +{ + return c != DBUS_TYPE_INVALID && strchr(basicTypes, c) != NULL; +} + +static bool isFixedType(int c) +{ + return c != DBUS_TYPE_INVALID && strchr(fixedTypes, c) != NULL; +} + +// Returns a pointer to one-past-end of this type if it's valid; +// returns NULL if it isn't valid. +static const char *validateSingleType(const char *signature) +{ + register char c = *signature; + if (c == DBUS_TYPE_INVALID) + return false; + + // is it one of the one-letter types? + if (strchr(oneLetterTypes, c) != NULL) + return signature + 1; + + // is it an array? + if (c == DBUS_TYPE_ARRAY) { + // then it's valid if the next type is valid + // or if it's a dict-entry + c = *++signature; + if (c == DBUS_DICT_ENTRY_BEGIN_CHAR) { + // beginning of a dictionary entry + // a dictionary entry has a key which is of basic types + // and a free value + c = *++signature; + if (!isBasicType(c)) + return 0; + signature = validateSingleType(signature + 1); + return signature && *signature == DBUS_DICT_ENTRY_END_CHAR ? signature + 1 : 0; + } + + return validateSingleType(signature); + } + + if (c == DBUS_STRUCT_BEGIN_CHAR) { + // beginning of a struct + ++signature; + while (true) { + signature = validateSingleType(signature); + if (!signature) + return 0; + if (*signature == DBUS_STRUCT_END_CHAR) + return signature + 1; + } + } + + // invalid/unknown type + return 0; +} + /*! \namespace QDBusUtil \inmodule QtDBus @@ -447,6 +509,25 @@ namespace QDBusUtil } /*! + \fn bool QDBusUtil::isValidBasicType(int type) + Returns true if \a c is a valid, basic D-Bus type. + */ + bool isValidBasicType(int c) + { + return isBasicType(c); + } + + /*! + \fn bool QDBusUtil::isValidFixedType(int type) + Returns true if \a c is a valid, fixed D-Bus type. + */ + bool isValidFixedType(int c) + { + return isFixedType(c); + } + + + /*! \fn bool QDBusUtil::isValidSignature(const QString &signature) Returns true if \a signature is a valid D-Bus type signature for one or more types. This function returns true if it can all of \a signature into valid, individual types and no @@ -456,7 +537,15 @@ namespace QDBusUtil */ bool isValidSignature(const QString &signature) { - return q_dbus_signature_validate(signature.toUtf8(), 0); + QByteArray ba = signature.toLatin1(); + const char *data = ba.constData(); + while (true) { + data = validateSingleType(data); + if (!data) + return false; + if (*data == '\0') + return true; + } } /*! @@ -467,7 +556,9 @@ namespace QDBusUtil */ bool isValidSingleSignature(const QString &signature) { - return q_dbus_signature_validate_single(signature.toUtf8(), 0); + QByteArray ba = signature.toLatin1(); + const char *data = validateSingleType(ba.constData()); + return data && *data == '\0'; } } // namespace QDBusUtil diff --git a/src/dbus/qdbusutil_p.h b/src/dbus/qdbusutil_p.h index 3721e98..24b5cea 100644 --- a/src/dbus/qdbusutil_p.h +++ b/src/dbus/qdbusutil_p.h @@ -81,6 +81,10 @@ namespace QDBusUtil Q_DBUS_EXPORT bool isValidObjectPath(const QString &path); + Q_DBUS_EXPORT bool isValidFixedType(int c); + + Q_DBUS_EXPORT bool isValidBasicType(int c); + Q_DBUS_EXPORT bool isValidSignature(const QString &signature); Q_DBUS_EXPORT bool isValidSingleSignature(const QString &signature); diff --git a/tests/auto/dbus.pro b/tests/auto/dbus.pro index e5f87e3..fe21475 100644 --- a/tests/auto/dbus.pro +++ b/tests/auto/dbus.pro @@ -14,6 +14,7 @@ SUBDIRS=\ qdbusperformance \ qdbusreply \ qdbusservicewatcher \ + qdbustype \ qdbusthreading \ qdbusxmlparser \ diff --git a/tests/auto/qdbustype/qdbustype.pro b/tests/auto/qdbustype/qdbustype.pro new file mode 100644 index 0000000..e2f0c90 --- /dev/null +++ b/tests/auto/qdbustype/qdbustype.pro @@ -0,0 +1,10 @@ +load(qttest_p4) +QT = core +contains(QT_CONFIG,dbus): { + SOURCES += tst_qdbustype.cpp + QT += dbus + QMAKE_CXXFLAGS += $$QT_CFLAGS_DBUS + LIBS_PRIVATE += $$QT_LIBS_DBUS +} else { + SOURCES += ../qdbusmarshall/dummy.cpp +} diff --git a/tests/auto/qdbustype/tst_qdbustype.cpp b/tests/auto/qdbustype/tst_qdbustype.cpp new file mode 100644 index 0000000..0469719 --- /dev/null +++ b/tests/auto/qdbustype/tst_qdbustype.cpp @@ -0,0 +1,271 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the FOO 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 +#include + +#include + +#include + +class tst_QDBusType : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void isValidFixedType_data(); + void isValidFixedType(); + void isValidBasicType_data(); + void isValidBasicType(); + void isValidSingleSignature_data(); + void isValidSingleSignature(); + void isValidArray_data(); + void isValidArray(); + void isValidSignature_data(); + void isValidSignature(); +}; + +enum { Invalid = false, Valid = true }; + +static void addColumns() +{ + // All tests use these two columns only + QTest::addColumn("data"); + QTest::addColumn("result"); + QTest::addColumn("isValid"); +} + +// ---- type adds --- +static void addFixedTypes() +{ + QTest::newRow("bool") << DBUS_TYPE_BOOLEAN_AS_STRING << true << true; + QTest::newRow("byte") << DBUS_TYPE_BYTE_AS_STRING << true << true; + QTest::newRow("int16") << DBUS_TYPE_INT16_AS_STRING << true << true; + QTest::newRow("uint16") << DBUS_TYPE_UINT16_AS_STRING << true << true; + QTest::newRow("int32") << DBUS_TYPE_INT32_AS_STRING << true << true; + QTest::newRow("uint32") << DBUS_TYPE_UINT32_AS_STRING << true << true; + QTest::newRow("int64") << DBUS_TYPE_INT64_AS_STRING << true << true; + QTest::newRow("uint64") << DBUS_TYPE_UINT64_AS_STRING << true << true; + QTest::newRow("double") << DBUS_TYPE_DOUBLE_AS_STRING << true << true; + QTest::newRow("unixfd") << "h" << true << true; +} + +static void addInvalidSingleLetterTypes() +{ + QChar nulString[] = { 0 }; + QTest::newRow("nul") << QString(nulString, 1) << false << false; + QTest::newRow("tilde") << "~" << false << false; + QTest::newRow("struct-begin") << "(" << false << false; + QTest::newRow("struct-end") << ")" << false << false; + QTest::newRow("dict-entry-begin") << "{" << false << false; + QTest::newRow("dict-entry-end") << "}" << false << false; + QTest::newRow("array-no-element") << "a" << false << false; +} + +static void addBasicTypes(bool basicsAreValid) +{ + addFixedTypes(); + QTest::newRow("string") << DBUS_TYPE_STRING_AS_STRING << basicsAreValid << true; + QTest::newRow("object-path") << DBUS_TYPE_OBJECT_PATH_AS_STRING << basicsAreValid << true; + QTest::newRow("signature") << DBUS_TYPE_SIGNATURE_AS_STRING << basicsAreValid << true; +} + +static void addVariant(bool variantIsValid) +{ + QTest::newRow("variant") << "v" << variantIsValid << true; +} + +static void addSingleSignatures() +{ + addBasicTypes(Valid); + addVariant(Valid); + QTest::newRow("struct-1") << "(y)" << true; + QTest::newRow("struct-2") << "(yy)" << true; + QTest::newRow("struct-3") << "(yyv)" << true; + + QTest::newRow("struct-nested-1") << "((y))" << true; + QTest::newRow("struct-nested-2") << "((yy))" << true; + QTest::newRow("struct-nested-3") << "(y(y))" << true; + QTest::newRow("struct-nested-4") << "((y)y)" << true; + QTest::newRow("struct-nested-5") << "(y(y)y)" << true; + QTest::newRow("struct-nested-6") << "((y)(y))" << true; + + QTest::newRow("array-1") << "as" << true; + QTest::newRow("struct-array-1") << "(as)" << true; + QTest::newRow("struct-array-2") << "(yas)" << true; + QTest::newRow("struct-array-3") << "(asy)" << true; + QTest::newRow("struct-array-4") << "(yasy)" << true; + + QTest::newRow("dict-1") << "a{sy}" << true; + QTest::newRow("dict-2") << "a{sv}" << true; + QTest::newRow("dict-struct-1") << "a{s(y)}" << true; + QTest::newRow("dict-struct-2") << "a{s(yyyy)}" << true; + QTest::newRow("dict-struct-array") << "a{s(ay)}" << true; + QTest::newRow("dict-array") << "a{sas}" << true; + QTest::newRow("dict-array-struct") << "a{sa(y)}" << true; + + addInvalidSingleLetterTypes(); + QTest::newRow("naked-dict-empty") << "{}" << false; + QTest::newRow("naked-dict-missing-value") << "{i}" << false; + + QTest::newRow("dict-empty") << "a{}" << false; + QTest::newRow("dict-missing-value") << "a{i}" << false; + QTest::newRow("dict-non-basic-key") << "a{vi}" << false; + QTest::newRow("dict-struct-key") << "a{(y)y}" << false; + QTest::newRow("dict-missing-close") << "a{sv" << false; + QTest::newRow("dict-mismatched-close") << "a{sv)" << false; + QTest::newRow("dict-missing-value-close") << "a{s" << false; + + QTest::newRow("empty-struct") << "()" << false; + QTest::newRow("struct-missing-close") << "(s" << false; + QTest::newRow("struct-nested-missing-close-1") << "((s)" << false; + QTest::newRow("struct-nested-missing-close-2") << "((s" << false; + + QTest::newRow("struct-ending-array-no-element") << "(a)" << false; +} + +static void addNakedDictEntry() +{ + QTest::newRow("naked-dict-entry") << "{sv}" << false; +} + +// ---- tests ---- + +void tst_QDBusType::isValidFixedType_data() +{ + addColumns(); + addFixedTypes(); + addBasicTypes(Invalid); + addVariant(Invalid); + addInvalidSingleLetterTypes(); +} + +void tst_QDBusType::isValidFixedType() +{ + QFETCH(QString, data); + QFETCH(bool, result); + QFETCH(bool, isValid); + Q_ASSERT_X(data.length() == 1, "tst_QDBusType", "Test is malformed, this function must test only one-letter types"); + Q_ASSERT(isValid || (!isValid && !result)); + + int type = data.at(0).unicode(); + if (isValid) + QCOMPARE(bool(dbus_type_is_fixed(type)), result); + QCOMPARE(QDBusUtil::isValidFixedType(type), result); +} + +void tst_QDBusType::isValidBasicType_data() +{ + addColumns(); + addBasicTypes(Valid); + addVariant(Invalid); + addInvalidSingleLetterTypes(); +} + +void tst_QDBusType::isValidBasicType() +{ + QFETCH(QString, data); + QFETCH(bool, result); + QFETCH(bool, isValid); + Q_ASSERT_X(data.length() == 1, "tst_QDBusType", "Test is malformed, this function must test only one-letter types"); + Q_ASSERT(isValid || (!isValid && !result)); + + int type = data.at(0).unicode(); + if (isValid) + QCOMPARE(bool(dbus_type_is_basic(type)), result); + QCOMPARE(QDBusUtil::isValidBasicType(type), result); +} + +void tst_QDBusType::isValidSingleSignature_data() +{ + addColumns(); + addSingleSignatures(); + addNakedDictEntry(); +} + +void tst_QDBusType::isValidSingleSignature() +{ + QFETCH(QString, data); + QFETCH(bool, result); + + QCOMPARE(bool(dbus_signature_validate_single(data.toLatin1(), 0)), result); + QCOMPARE(QDBusUtil::isValidSingleSignature(data), result); +} + +void tst_QDBusType::isValidArray_data() +{ + addColumns(); + addSingleSignatures(); +} + +void tst_QDBusType::isValidArray() +{ + QFETCH(QString, data); + QFETCH(bool, result); + + data.prepend("a"); + QCOMPARE(bool(dbus_signature_validate_single(data.toLatin1(), 0)), result); + QCOMPARE(QDBusUtil::isValidSingleSignature(data), result); + + data.prepend("a"); + QCOMPARE(bool(dbus_signature_validate_single(data.toLatin1(), 0)), result); + QCOMPARE(QDBusUtil::isValidSingleSignature(data), result); +} + +void tst_QDBusType::isValidSignature_data() +{ + isValidSingleSignature_data(); +} + +void tst_QDBusType::isValidSignature() +{ + QFETCH(QString, data); + QFETCH(bool, result); + + data.append(data); + if (data.at(0).unicode()) + QCOMPARE(bool(dbus_signature_validate(data.toLatin1(), 0)), result); + QCOMPARE(QDBusUtil::isValidSignature(data), result); +} + +QTEST_MAIN(tst_QDBusType) + +#include "tst_qdbustype.moc" -- cgit v0.12 From 08cecc882bf23253b3e447cde037e10529f56cdf Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 21 Feb 2011 20:15:31 +0100 Subject: Use the Qt code for validating types in QtDBus --- src/dbus/qdbus_symbols_p.h | 12 ------------ src/dbus/qdbusmarshaller.cpp | 6 +++--- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/dbus/qdbus_symbols_p.h b/src/dbus/qdbus_symbols_p.h index d0a4b3e..039657e 100644 --- a/src/dbus/qdbus_symbols_p.h +++ b/src/dbus/qdbus_symbols_p.h @@ -358,18 +358,6 @@ DEFINEFUNC(dbus_bool_t , dbus_server_set_watch_functions, (DBusServer DEFINEFUNC(void , dbus_server_unref, (DBusServer *server), (server), ) -/* dbus-signature.h */ -DEFINEFUNC(dbus_bool_t , dbus_signature_validate, (const char *signature, - DBusError *error), - (signature, error), return) -DEFINEFUNC(dbus_bool_t , dbus_signature_validate_single, (const char *signature, - DBusError *error), - (signature, error), return) -DEFINEFUNC(dbus_bool_t , dbus_type_is_basic, (int typecode), - (typecode), return) -DEFINEFUNC(dbus_bool_t , dbus_type_is_fixed, (int typecode), - (typecode), return) - /* dbus-thread.h */ DEFINEFUNC(dbus_bool_t , dbus_threads_init_default, (), (), return) diff --git a/src/dbus/qdbusmarshaller.cpp b/src/dbus/qdbusmarshaller.cpp index edf743e..6dec359 100644 --- a/src/dbus/qdbusmarshaller.cpp +++ b/src/dbus/qdbusmarshaller.cpp @@ -254,7 +254,7 @@ inline QDBusMarshaller *QDBusMarshaller::beginMap(int kid, int vid) .arg(QLatin1String(QVariant::typeToName(QVariant::Type(kid))))); return this; } - if (ksignature[1] != 0 || !q_dbus_type_is_basic(*ksignature)) { + if (ksignature[1] != 0 || !QDBusUtil::isValidBasicType(*ksignature)) { qWarning("QDBusMarshaller: type '%s' (%d) cannot be used as the key type in a D-BUS map.", QVariant::typeToName( QVariant::Type(kid) ), kid); error(QString::fromLatin1("Type %1 passed in arguments cannot be used as a key in a map") @@ -511,7 +511,7 @@ bool QDBusMarshaller::appendRegisteredType(const QVariant &arg) bool QDBusMarshaller::appendCrossMarshalling(QDBusDemarshaller *demarshaller) { int code = q_dbus_message_iter_get_arg_type(&demarshaller->iterator); - if (q_dbus_type_is_basic(code)) { + if (QDBusUtil::isValidBasicType(code)) { // easy: just append // do exactly like the D-BUS docs suggest // (see apidocs for q_dbus_message_iter_get_basic) @@ -525,7 +525,7 @@ bool QDBusMarshaller::appendCrossMarshalling(QDBusDemarshaller *demarshaller) if (code == DBUS_TYPE_ARRAY) { int element = q_dbus_message_iter_get_element_type(&demarshaller->iterator); - if (q_dbus_type_is_fixed(element) && element != DBUS_TYPE_UNIX_FD) { + if (QDBusUtil::isValidFixedType(element) && element != DBUS_TYPE_UNIX_FD) { // another optimization: fixed size arrays // code is exactly like QDBusDemarshaller::toByteArray DBusMessageIter sub; -- cgit v0.12 From c22f52ce22f998d35ccc6ee0caa60d4e0af3b783 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 23 Feb 2011 16:59:54 +0100 Subject: Move the QDBusPerformance test to the tests/benchmark dir --- tests/auto/dbus.pro | 1 - tests/auto/qdbusperformance/.gitignore | 2 - tests/auto/qdbusperformance/qdbusperformance.pro | 8 - tests/auto/qdbusperformance/server/server.cpp | 64 ------ tests/auto/qdbusperformance/server/server.pro | 5 - tests/auto/qdbusperformance/serverobject.h | 115 ----------- tests/auto/qdbusperformance/test/test.pro | 7 - .../auto/qdbusperformance/tst_qdbusperformance.cpp | 230 --------------------- tests/benchmarks/benchmarks.pro | 1 + tests/benchmarks/dbus/dbus.pro | 3 + tests/benchmarks/dbus/qdbusperformance/.gitignore | 2 + .../dbus/qdbusperformance/qdbusperformance.pro | 4 + .../dbus/qdbusperformance/server/server.cpp | 64 ++++++ .../dbus/qdbusperformance/server/server.pro | 5 + .../dbus/qdbusperformance/serverobject.h | 115 +++++++++++ .../benchmarks/dbus/qdbusperformance/test/test.pro | 7 + .../dbus/qdbusperformance/tst_qdbusperformance.cpp | 230 +++++++++++++++++++++ 17 files changed, 431 insertions(+), 432 deletions(-) delete mode 100644 tests/auto/qdbusperformance/.gitignore delete mode 100644 tests/auto/qdbusperformance/qdbusperformance.pro delete mode 100644 tests/auto/qdbusperformance/server/server.cpp delete mode 100644 tests/auto/qdbusperformance/server/server.pro delete mode 100644 tests/auto/qdbusperformance/serverobject.h delete mode 100644 tests/auto/qdbusperformance/test/test.pro delete mode 100644 tests/auto/qdbusperformance/tst_qdbusperformance.cpp create mode 100644 tests/benchmarks/dbus/dbus.pro create mode 100644 tests/benchmarks/dbus/qdbusperformance/.gitignore create mode 100644 tests/benchmarks/dbus/qdbusperformance/qdbusperformance.pro create mode 100644 tests/benchmarks/dbus/qdbusperformance/server/server.cpp create mode 100644 tests/benchmarks/dbus/qdbusperformance/server/server.pro create mode 100644 tests/benchmarks/dbus/qdbusperformance/serverobject.h create mode 100644 tests/benchmarks/dbus/qdbusperformance/test/test.pro create mode 100644 tests/benchmarks/dbus/qdbusperformance/tst_qdbusperformance.cpp diff --git a/tests/auto/dbus.pro b/tests/auto/dbus.pro index fe21475..31b46a3 100644 --- a/tests/auto/dbus.pro +++ b/tests/auto/dbus.pro @@ -11,7 +11,6 @@ SUBDIRS=\ qdbusmetatype \ qdbuspendingcall \ qdbuspendingreply \ - qdbusperformance \ qdbusreply \ qdbusservicewatcher \ qdbustype \ diff --git a/tests/auto/qdbusperformance/.gitignore b/tests/auto/qdbusperformance/.gitignore deleted file mode 100644 index 4cd8399..0000000 --- a/tests/auto/qdbusperformance/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -tst_qdbusperformance -server/server diff --git a/tests/auto/qdbusperformance/qdbusperformance.pro b/tests/auto/qdbusperformance/qdbusperformance.pro deleted file mode 100644 index 6880518..0000000 --- a/tests/auto/qdbusperformance/qdbusperformance.pro +++ /dev/null @@ -1,8 +0,0 @@ -load(qttest_p4) -contains(QT_CONFIG,dbus): { - TEMPLATE = subdirs - CONFIG += ordered - SUBDIRS = server test -} else { - SOURCES += ../qdbusmarshall/dummy.cpp -} diff --git a/tests/auto/qdbusperformance/server/server.cpp b/tests/auto/qdbusperformance/server/server.cpp deleted file mode 100644 index 3bd5efc..0000000 --- a/tests/auto/qdbusperformance/server/server.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the test suite 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 -#include - -#include "../serverobject.h" - -static const char serviceName[] = "com.trolltech.autotests.performance"; -static const char objectPath[] = "/"; - -int main(int argc, char *argv[]) -{ - QCoreApplication app(argc, argv); - - QDBusConnection con = QDBusConnection::sessionBus(); - if (!con.isConnected()) - exit(1); - - if (!con.registerService(serviceName)) - exit(2); - - ServerObject obj(objectPath, con); - printf("ready.\n"); - return app.exec(); -} - diff --git a/tests/auto/qdbusperformance/server/server.pro b/tests/auto/qdbusperformance/server/server.pro deleted file mode 100644 index 30f81dd..0000000 --- a/tests/auto/qdbusperformance/server/server.pro +++ /dev/null @@ -1,5 +0,0 @@ -SOURCES = server.cpp -HEADERS = ../serverobject.h -TARGET = server -CONFIG += qdbus -QT -= gui diff --git a/tests/auto/qdbusperformance/serverobject.h b/tests/auto/qdbusperformance/serverobject.h deleted file mode 100644 index 6f85bb4..0000000 --- a/tests/auto/qdbusperformance/serverobject.h +++ /dev/null @@ -1,115 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the test suite 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$ -** -****************************************************************************/ - - -#ifndef SERVEROBJECT_H -#define SERVEROBJECT_H - -#include -#include - -class ServerObject: public QObject -{ - Q_OBJECT - Q_CLASSINFO("D-Bus Interface", "com.trolltech.autotests.Performance") -public: - ServerObject(const QString &objectPath, QDBusConnection conn, QObject *parent = 0) - : QObject(parent) - { - conn.registerObject(objectPath, this, QDBusConnection::ExportAllSlots); - } - -public slots: - Q_NOREPLY void noReply(const QByteArray &) - { - // black hole - } - Q_NOREPLY void noReply(const QString &) - { - // black hole - } - Q_NOREPLY void noReply(const QDBusVariant &) - { - // black hole - } - - int size(const QByteArray &data) - { - return data.size(); - } - int size(const QString &data) - { - return data.size(); - } - int size(const QDBusVariant &data) - { - QVariant v = data.variant(); - switch (v.type()) - { - case QVariant::ByteArray: - return v.toByteArray().size(); - case QVariant::StringList: - return v.toStringList().size(); - case QVariant::String: - default: - return v.toString().size(); - } - } - - QByteArray echo(const QByteArray &data) - { - return data; - } - QString echo(const QString &data) - { - return data; - } - QDBusVariant echo(const QDBusVariant &data) - { - return data; - } - - void nothing() - { - } -}; - -#endif diff --git a/tests/auto/qdbusperformance/test/test.pro b/tests/auto/qdbusperformance/test/test.pro deleted file mode 100644 index 9f5712e..0000000 --- a/tests/auto/qdbusperformance/test/test.pro +++ /dev/null @@ -1,7 +0,0 @@ -load(qttest_p4) -SOURCES += ../tst_qdbusperformance.cpp -HEADERS += ../serverobject.h -TARGET = ../tst_qdbusperformance - -QT = core -CONFIG += qdbus diff --git a/tests/auto/qdbusperformance/tst_qdbusperformance.cpp b/tests/auto/qdbusperformance/tst_qdbusperformance.cpp deleted file mode 100644 index a5b4b98..0000000 --- a/tests/auto/qdbusperformance/tst_qdbusperformance.cpp +++ /dev/null @@ -1,230 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the test suite 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 -#include -#include - -#include "./serverobject.h" - -static const char serviceName[] = "com.trolltech.autotests.performance"; -static const int runTime = 500; - -class tst_QDBusPerformance: public QObject -{ - Q_OBJECT - QProcess proc; - QDBusInterface *target; - - QDBusInterface *remote; - QDBusInterface *local; - - bool executeTest(const char *funcname, int size, const QVariant &data); - -public slots: - void initTestCase_data(); - void initTestCase(); - void init(); - -private slots: - void callSpeed(); - - void oneWay_data(); - void oneWay(); - void oneWayVariant_data(); - void oneWayVariant(); - - void roundTrip_data(); - void roundTrip(); - void roundTripVariant_data(); - void roundTripVariant(); -}; -Q_DECLARE_METATYPE(QVariant) - -void tst_QDBusPerformance::initTestCase() -{ - QDBusConnection con = QDBusConnection::sessionBus(); - QVERIFY(con.isConnected()); - - QDBusServiceWatcher watcher(serviceName, con, - QDBusServiceWatcher::WatchForRegistration); - connect(&watcher, SIGNAL(serviceRegistered(QString)), - &QTestEventLoop::instance(), SLOT(exitLoop())); - -#ifdef Q_OS_WIN - proc.start("server"); -#else - proc.start("./server/server"); -#endif - QVERIFY(proc.waitForStarted()); - - QTestEventLoop::instance().enterLoop(5); - QVERIFY(con.interface()->isServiceRegistered(serviceName)); - - remote = new QDBusInterface(serviceName, "/", "com.trolltech.autotests.Performance", con, this); - QVERIFY(remote->isValid()); - - new ServerObject("/", con, this); - local = new QDBusInterface(con.baseService(), "/", "com.trolltech.autotests.Performance", con, this); - QVERIFY(local->isValid()); -} - -void tst_QDBusPerformance::initTestCase_data() -{ - QTest::addColumn("loopback"); - - QTest::newRow("normal") << false; - QTest::newRow("loopback") << true; -} - -void tst_QDBusPerformance::init() -{ - QFETCH_GLOBAL(bool, loopback); - if (loopback) - target = local; - else - target = remote; -} - -void tst_QDBusPerformance::callSpeed() -{ - QElapsedTimer timer; - - int callCount = 0; - timer.start(); - while (timer.elapsed() < runTime) { - QDBusReply reply = target->call("nothing"); - QVERIFY(reply.isValid()); - - ++callCount; - } - qDebug() << callCount << "calls in" << timer.elapsed() << "ms:" - << (callCount * 1000.0 / timer.elapsed()) << "calls/sec"; -} - -bool tst_QDBusPerformance::executeTest(const char *funcname, int size, const QVariant &data) -{ - QElapsedTimer timer; - - int callCount = 0; - qint64 transferred = 0; - timer.start(); - while (timer.elapsed() < runTime) { - QDBusMessage reply = target->call(funcname, data); - if (reply.type() != QDBusMessage::ReplyMessage) - return false; - - transferred += size; - ++callCount; - } - qDebug() << transferred << "bytes in" << timer.elapsed() << "ms" - << "(in" << callCount << "calls):" - << (transferred * 1000.0 / timer.elapsed() / 1024 / 1024) << "MB/s"; - - return true; -} - -void tst_QDBusPerformance::oneWay_data() -{ - QTest::addColumn("data"); - QTest::addColumn("size"); - - QByteArray ba(256, 'a'); - while (ba.size() < 8193) { - QTest::newRow(QString("%1-byteArray").arg(ba.size()).toAscii()) << qVariantFromValue(ba) << ba.size(); - ba += ba; - } - - QString s(256, QLatin1Char('a')); - while (s.size() < 8193) { - QTest::newRow(QString("%1-string").arg(s.size()).toAscii()) << qVariantFromValue(s) << s.size(); - s += s; - } -} - -void tst_QDBusPerformance::oneWay() -{ - QFETCH(QVariant, data); - QFETCH(int, size); - - QVERIFY(executeTest("size", size, data)); -} - -void tst_QDBusPerformance::oneWayVariant_data() -{ - oneWay_data(); -} - -void tst_QDBusPerformance::oneWayVariant() -{ - QFETCH(QVariant, data); - QFETCH(int, size); - - QVERIFY(executeTest("size", size, qVariantFromValue(QDBusVariant(data)))); -} - -void tst_QDBusPerformance::roundTrip_data() -{ - oneWay_data(); -} - -void tst_QDBusPerformance::roundTrip() -{ - QFETCH(QVariant, data); - QFETCH(int, size); - - QVERIFY(executeTest("echo", size, data)); -} - -void tst_QDBusPerformance::roundTripVariant_data() -{ - oneWay_data(); -} - -void tst_QDBusPerformance::roundTripVariant() -{ - QFETCH(QVariant, data); - QFETCH(int, size); - - QVERIFY(executeTest("echo", size, qVariantFromValue(QDBusVariant(data)))); -} - -QTEST_MAIN(tst_QDBusPerformance) -#include "tst_qdbusperformance.moc" diff --git a/tests/benchmarks/benchmarks.pro b/tests/benchmarks/benchmarks.pro index 00a1b37..b5e3a4b 100644 --- a/tests/benchmarks/benchmarks.pro +++ b/tests/benchmarks/benchmarks.pro @@ -7,6 +7,7 @@ SUBDIRS = \ svg contains(QT_CONFIG, opengl): SUBDIRS += opengl contains(QT_CONFIG, declarative): SUBDIRS += declarative +contains(QT_CONFIG, dbus): SUBDIRS += dbus check-trusted.CONFIG += recursive QMAKE_EXTRA_TARGETS += check-trusted diff --git a/tests/benchmarks/dbus/dbus.pro b/tests/benchmarks/dbus/dbus.pro new file mode 100644 index 0000000..b02d070 --- /dev/null +++ b/tests/benchmarks/dbus/dbus.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs +SUBDIRS = \ + qdbusperformance diff --git a/tests/benchmarks/dbus/qdbusperformance/.gitignore b/tests/benchmarks/dbus/qdbusperformance/.gitignore new file mode 100644 index 0000000..4cd8399 --- /dev/null +++ b/tests/benchmarks/dbus/qdbusperformance/.gitignore @@ -0,0 +1,2 @@ +tst_qdbusperformance +server/server diff --git a/tests/benchmarks/dbus/qdbusperformance/qdbusperformance.pro b/tests/benchmarks/dbus/qdbusperformance/qdbusperformance.pro new file mode 100644 index 0000000..90f88a7 --- /dev/null +++ b/tests/benchmarks/dbus/qdbusperformance/qdbusperformance.pro @@ -0,0 +1,4 @@ +load(qttest_p4) +TEMPLATE = subdirs +CONFIG += ordered +SUBDIRS = server test diff --git a/tests/benchmarks/dbus/qdbusperformance/server/server.cpp b/tests/benchmarks/dbus/qdbusperformance/server/server.cpp new file mode 100644 index 0000000..3bd5efc --- /dev/null +++ b/tests/benchmarks/dbus/qdbusperformance/server/server.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite 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 +#include + +#include "../serverobject.h" + +static const char serviceName[] = "com.trolltech.autotests.performance"; +static const char objectPath[] = "/"; + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + + QDBusConnection con = QDBusConnection::sessionBus(); + if (!con.isConnected()) + exit(1); + + if (!con.registerService(serviceName)) + exit(2); + + ServerObject obj(objectPath, con); + printf("ready.\n"); + return app.exec(); +} + diff --git a/tests/benchmarks/dbus/qdbusperformance/server/server.pro b/tests/benchmarks/dbus/qdbusperformance/server/server.pro new file mode 100644 index 0000000..30f81dd --- /dev/null +++ b/tests/benchmarks/dbus/qdbusperformance/server/server.pro @@ -0,0 +1,5 @@ +SOURCES = server.cpp +HEADERS = ../serverobject.h +TARGET = server +CONFIG += qdbus +QT -= gui diff --git a/tests/benchmarks/dbus/qdbusperformance/serverobject.h b/tests/benchmarks/dbus/qdbusperformance/serverobject.h new file mode 100644 index 0000000..6f85bb4 --- /dev/null +++ b/tests/benchmarks/dbus/qdbusperformance/serverobject.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite 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$ +** +****************************************************************************/ + + +#ifndef SERVEROBJECT_H +#define SERVEROBJECT_H + +#include +#include + +class ServerObject: public QObject +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "com.trolltech.autotests.Performance") +public: + ServerObject(const QString &objectPath, QDBusConnection conn, QObject *parent = 0) + : QObject(parent) + { + conn.registerObject(objectPath, this, QDBusConnection::ExportAllSlots); + } + +public slots: + Q_NOREPLY void noReply(const QByteArray &) + { + // black hole + } + Q_NOREPLY void noReply(const QString &) + { + // black hole + } + Q_NOREPLY void noReply(const QDBusVariant &) + { + // black hole + } + + int size(const QByteArray &data) + { + return data.size(); + } + int size(const QString &data) + { + return data.size(); + } + int size(const QDBusVariant &data) + { + QVariant v = data.variant(); + switch (v.type()) + { + case QVariant::ByteArray: + return v.toByteArray().size(); + case QVariant::StringList: + return v.toStringList().size(); + case QVariant::String: + default: + return v.toString().size(); + } + } + + QByteArray echo(const QByteArray &data) + { + return data; + } + QString echo(const QString &data) + { + return data; + } + QDBusVariant echo(const QDBusVariant &data) + { + return data; + } + + void nothing() + { + } +}; + +#endif diff --git a/tests/benchmarks/dbus/qdbusperformance/test/test.pro b/tests/benchmarks/dbus/qdbusperformance/test/test.pro new file mode 100644 index 0000000..9f5712e --- /dev/null +++ b/tests/benchmarks/dbus/qdbusperformance/test/test.pro @@ -0,0 +1,7 @@ +load(qttest_p4) +SOURCES += ../tst_qdbusperformance.cpp +HEADERS += ../serverobject.h +TARGET = ../tst_qdbusperformance + +QT = core +CONFIG += qdbus diff --git a/tests/benchmarks/dbus/qdbusperformance/tst_qdbusperformance.cpp b/tests/benchmarks/dbus/qdbusperformance/tst_qdbusperformance.cpp new file mode 100644 index 0000000..a5b4b98 --- /dev/null +++ b/tests/benchmarks/dbus/qdbusperformance/tst_qdbusperformance.cpp @@ -0,0 +1,230 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite 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 +#include +#include + +#include "./serverobject.h" + +static const char serviceName[] = "com.trolltech.autotests.performance"; +static const int runTime = 500; + +class tst_QDBusPerformance: public QObject +{ + Q_OBJECT + QProcess proc; + QDBusInterface *target; + + QDBusInterface *remote; + QDBusInterface *local; + + bool executeTest(const char *funcname, int size, const QVariant &data); + +public slots: + void initTestCase_data(); + void initTestCase(); + void init(); + +private slots: + void callSpeed(); + + void oneWay_data(); + void oneWay(); + void oneWayVariant_data(); + void oneWayVariant(); + + void roundTrip_data(); + void roundTrip(); + void roundTripVariant_data(); + void roundTripVariant(); +}; +Q_DECLARE_METATYPE(QVariant) + +void tst_QDBusPerformance::initTestCase() +{ + QDBusConnection con = QDBusConnection::sessionBus(); + QVERIFY(con.isConnected()); + + QDBusServiceWatcher watcher(serviceName, con, + QDBusServiceWatcher::WatchForRegistration); + connect(&watcher, SIGNAL(serviceRegistered(QString)), + &QTestEventLoop::instance(), SLOT(exitLoop())); + +#ifdef Q_OS_WIN + proc.start("server"); +#else + proc.start("./server/server"); +#endif + QVERIFY(proc.waitForStarted()); + + QTestEventLoop::instance().enterLoop(5); + QVERIFY(con.interface()->isServiceRegistered(serviceName)); + + remote = new QDBusInterface(serviceName, "/", "com.trolltech.autotests.Performance", con, this); + QVERIFY(remote->isValid()); + + new ServerObject("/", con, this); + local = new QDBusInterface(con.baseService(), "/", "com.trolltech.autotests.Performance", con, this); + QVERIFY(local->isValid()); +} + +void tst_QDBusPerformance::initTestCase_data() +{ + QTest::addColumn("loopback"); + + QTest::newRow("normal") << false; + QTest::newRow("loopback") << true; +} + +void tst_QDBusPerformance::init() +{ + QFETCH_GLOBAL(bool, loopback); + if (loopback) + target = local; + else + target = remote; +} + +void tst_QDBusPerformance::callSpeed() +{ + QElapsedTimer timer; + + int callCount = 0; + timer.start(); + while (timer.elapsed() < runTime) { + QDBusReply reply = target->call("nothing"); + QVERIFY(reply.isValid()); + + ++callCount; + } + qDebug() << callCount << "calls in" << timer.elapsed() << "ms:" + << (callCount * 1000.0 / timer.elapsed()) << "calls/sec"; +} + +bool tst_QDBusPerformance::executeTest(const char *funcname, int size, const QVariant &data) +{ + QElapsedTimer timer; + + int callCount = 0; + qint64 transferred = 0; + timer.start(); + while (timer.elapsed() < runTime) { + QDBusMessage reply = target->call(funcname, data); + if (reply.type() != QDBusMessage::ReplyMessage) + return false; + + transferred += size; + ++callCount; + } + qDebug() << transferred << "bytes in" << timer.elapsed() << "ms" + << "(in" << callCount << "calls):" + << (transferred * 1000.0 / timer.elapsed() / 1024 / 1024) << "MB/s"; + + return true; +} + +void tst_QDBusPerformance::oneWay_data() +{ + QTest::addColumn("data"); + QTest::addColumn("size"); + + QByteArray ba(256, 'a'); + while (ba.size() < 8193) { + QTest::newRow(QString("%1-byteArray").arg(ba.size()).toAscii()) << qVariantFromValue(ba) << ba.size(); + ba += ba; + } + + QString s(256, QLatin1Char('a')); + while (s.size() < 8193) { + QTest::newRow(QString("%1-string").arg(s.size()).toAscii()) << qVariantFromValue(s) << s.size(); + s += s; + } +} + +void tst_QDBusPerformance::oneWay() +{ + QFETCH(QVariant, data); + QFETCH(int, size); + + QVERIFY(executeTest("size", size, data)); +} + +void tst_QDBusPerformance::oneWayVariant_data() +{ + oneWay_data(); +} + +void tst_QDBusPerformance::oneWayVariant() +{ + QFETCH(QVariant, data); + QFETCH(int, size); + + QVERIFY(executeTest("size", size, qVariantFromValue(QDBusVariant(data)))); +} + +void tst_QDBusPerformance::roundTrip_data() +{ + oneWay_data(); +} + +void tst_QDBusPerformance::roundTrip() +{ + QFETCH(QVariant, data); + QFETCH(int, size); + + QVERIFY(executeTest("echo", size, data)); +} + +void tst_QDBusPerformance::roundTripVariant_data() +{ + oneWay_data(); +} + +void tst_QDBusPerformance::roundTripVariant() +{ + QFETCH(QVariant, data); + QFETCH(int, size); + + QVERIFY(executeTest("echo", size, qVariantFromValue(QDBusVariant(data)))); +} + +QTEST_MAIN(tst_QDBusPerformance) +#include "tst_qdbusperformance.moc" -- cgit v0.12 From eb0262ae71d4a8576cd8ba5885d8218c9f566371 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 23 Feb 2011 17:02:23 +0100 Subject: Add a benchmark for testing our QtDBus type-validation Our code is much faster than libdbus-1, even when built in debug mode. --- tests/benchmarks/dbus/dbus.pro | 3 +- tests/benchmarks/dbus/qdbustype/main.cpp | 115 ++++++++++++++++++++++++++ tests/benchmarks/dbus/qdbustype/qdbustype.pro | 8 ++ 3 files changed, 125 insertions(+), 1 deletion(-) create mode 100644 tests/benchmarks/dbus/qdbustype/main.cpp create mode 100644 tests/benchmarks/dbus/qdbustype/qdbustype.pro diff --git a/tests/benchmarks/dbus/dbus.pro b/tests/benchmarks/dbus/dbus.pro index b02d070..989a0db 100644 --- a/tests/benchmarks/dbus/dbus.pro +++ b/tests/benchmarks/dbus/dbus.pro @@ -1,3 +1,4 @@ TEMPLATE = subdirs SUBDIRS = \ - qdbusperformance + qdbusperformance \ + qdbustype diff --git a/tests/benchmarks/dbus/qdbustype/main.cpp b/tests/benchmarks/dbus/qdbustype/main.cpp new file mode 100644 index 0000000..abaae7e --- /dev/null +++ b/tests/benchmarks/dbus/qdbustype/main.cpp @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the FOO 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 +#include + +#include + +#include + +class tst_QDBusType: public QObject +{ + Q_OBJECT +private Q_SLOTS: + void benchmarkSignature_data(); + void benchmarkSignature(); +}; + +static inline void benchmarkAddRow(const char *name, const char *data) +{ + QTest::newRow(QByteArray("native-") + name) << data << true; + QTest::newRow(name) << data << false; +} + +void tst_QDBusType::benchmarkSignature_data() +{ + QTest::addColumn("data"); + QTest::addColumn("useNative"); + + for (int loopCount = 0; loopCount < 2; ++loopCount) { + bool useNative = loopCount; + QByteArray prefix = useNative ? "native-" : ""; + + benchmarkAddRow("single-invalid", "~"); + benchmarkAddRow("single-invalid-array", "a~"); + benchmarkAddRow("single-invalid-struct", "(.)"); + + benchmarkAddRow("single-char", "b"); + benchmarkAddRow("single-array", "as"); + benchmarkAddRow("single-simplestruct", "(y)"); + benchmarkAddRow("single-simpledict", "a{sv}"); + benchmarkAddRow("single-complexdict", "a{s(aya{io})}"); + + benchmarkAddRow("multiple-char", "ssg"); + benchmarkAddRow("multiple-arrays", "asasay"); + + benchmarkAddRow("struct-missingclose", "(ayyyy"); + benchmarkAddRow("longstruct", "(yyyyyyayasy)"); + benchmarkAddRow("invalid-longstruct", "(yyyyyyayas.y)"); + benchmarkAddRow("complexstruct", "(y(aasay)oga{sv})"); + benchmarkAddRow("multiple-simple-structs", "(y)(y)(y)"); + } +} + +void tst_QDBusType::benchmarkSignature() +{ + QFETCH(QString, data); + QFETCH(bool, useNative); + + bool result; + if (useNative) { + dbus_signature_validate(data.toLatin1(), 0); + QBENCHMARK { + result = dbus_signature_validate(data.toLatin1(), 0); + } + } else { + QDBusUtil::isValidSignature(data); + QBENCHMARK { + result = QDBusUtil::isValidSignature(data); + } + } + Q_UNUSED(result); +} + +QTEST_MAIN(tst_QDBusType) + +#include "main.moc" diff --git a/tests/benchmarks/dbus/qdbustype/qdbustype.pro b/tests/benchmarks/dbus/qdbustype/qdbustype.pro new file mode 100644 index 0000000..d480a05 --- /dev/null +++ b/tests/benchmarks/dbus/qdbustype/qdbustype.pro @@ -0,0 +1,8 @@ +load(qttest_p4) +TARGET = tst_bench_qdbustype +QT -= gui +QT += dbus +QMAKE_CXXFLAGS += $$QT_CFLAGS_DBUS +LIBS_PRIVATE += $$QT_LIBS_DBUS + +SOURCES += main.cpp -- cgit v0.12 From 162ee8d83c72990c33952a99bd959f18842dde10 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Fri, 28 Jan 2011 11:14:46 +0100 Subject: Change the error message in the timer ID deallocator. This is really an internal error since the upper layers of the event dispatcher should have already caught a timer ID that isn't valid. Reviewed-By: Olivier Goffart --- src/corelib/kernel/qabstracteventdispatcher.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/corelib/kernel/qabstracteventdispatcher.cpp b/src/corelib/kernel/qabstracteventdispatcher.cpp index e79f87a..07f04b2 100644 --- a/src/corelib/kernel/qabstracteventdispatcher.cpp +++ b/src/corelib/kernel/qabstracteventdispatcher.cpp @@ -187,7 +187,8 @@ void QAbstractEventDispatcherPrivate::releaseTimerId(int timerId) int at = bucketIndex(bucket, which); int *b = timerIds[bucket]; - Q_ASSERT(b[at] == -timerId); + Q_ASSERT_X(timerId == -b[at], "QAbstractEventDispatcher::releaseTimerId", + "Internal error: timer ID not found"); int freeId, newTimerId; do { -- cgit v0.12 From 8f08be2bd372c581d578ed81c2f57cf1adc0ae79 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 13 Dec 2010 17:22:33 +0100 Subject: Change the number of entries in the first timer bucket. 8 timers are too few for common applications. 32 is more likely to reach >90% of the applications. This way, we avoid a memory allocation. Reviewed-by: Olivier Goffart --- src/corelib/kernel/qabstracteventdispatcher.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/corelib/kernel/qabstracteventdispatcher.cpp b/src/corelib/kernel/qabstracteventdispatcher.cpp index 07f04b2..b1b1380 100644 --- a/src/corelib/kernel/qabstracteventdispatcher.cpp +++ b/src/corelib/kernel/qabstracteventdispatcher.cpp @@ -49,14 +49,18 @@ QT_BEGIN_NAMESPACE // we allow for 2^24 = 8^8 = 16777216 simultaneously running timers -enum { NumberOfBuckets = 8, FirstBucketSize = 8 }; +enum { NumberOfBuckets = 8, FirstBucketSize = 32 }; static const int BucketSize[NumberOfBuckets] = - { 8, 64, 512, 4096, 32768, 262144, 2097152, 16777216 - 2396744 }; + { 32, 64, 512, 4096, 32768, 262144, 2097152, 16777216 - 2364000 }; static const int BucketOffset[NumberOfBuckets] = - { 0, 8, 72, 584, 4680, 37448, 299592, 2396744 }; + { 0, 32, 96, 608, 4704, 37448, 266848, 2364000 }; + +static int FirstBucket[] = { + 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 +}; -static int FirstBucket[FirstBucketSize] = { 1, 2, 3, 4, 5, 6, 7, 8 }; static QBasicAtomicPointer timerIds[NumberOfBuckets] = { Q_BASIC_ATOMIC_INITIALIZER(FirstBucket), Q_BASIC_ATOMIC_INITIALIZER(0), -- cgit v0.12 From 52187b084491641ef80536c743c2261af8bfe11c Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Wed, 13 Apr 2011 16:34:06 +1000 Subject: Moving contentY by large values in List/GridView is slow We needed to create/destroy every delegate between the current position and the new position. Now we estimate element at the new position and just create the elements from that item. Change-Id: I9da1354cbadb4e44fafc1a0bee619d058d1e06a2 Task-number: QTBUG-14974 Reviewed-by: Bea Lam --- .../graphicsitems/qdeclarativegridview.cpp | 20 ++++++++ .../graphicsitems/qdeclarativelistview.cpp | 22 +++++++++ .../tst_qdeclarativegridview.cpp | 51 ++++++++++++++++++++ .../tst_qdeclarativelistview.cpp | 56 ++++++++++++++++++++++ 4 files changed, 149 insertions(+) diff --git a/src/declarative/graphicsitems/qdeclarativegridview.cpp b/src/declarative/graphicsitems/qdeclarativegridview.cpp index 3ec29c1..21bfc59 100644 --- a/src/declarative/graphicsitems/qdeclarativegridview.cpp +++ b/src/declarative/graphicsitems/qdeclarativegridview.cpp @@ -584,6 +584,26 @@ void QDeclarativeGridViewPrivate::refill(qreal from, qreal to, bool doBuffer) --i; modelIndex = visibleItems.at(i)->index + 1; } + + if (visibleItems.count() && (fillFrom > rowPos + rowSize()*2 + || fillTo < rowPosAt(visibleIndex) - rowSize())) { + // We've jumped more than a page. Estimate which items are now + // visible and fill from there. + int count = (fillFrom - (rowPos + rowSize())) / (rowSize()) * columns; + for (int i = 0; i < visibleItems.count(); ++i) + releaseItem(visibleItems.at(i)); + visibleItems.clear(); + modelIndex += count; + if (modelIndex >= model->count()) + modelIndex = model->count() - 1; + else if (modelIndex < 0) + modelIndex = 0; + modelIndex = modelIndex / columns * columns; + visibleIndex = modelIndex; + colPos = colPosAt(visibleIndex); + rowPos = rowPosAt(visibleIndex); + } + int colNum = colPos / colSize(); FxGridItem *item = 0; diff --git a/src/declarative/graphicsitems/qdeclarativelistview.cpp b/src/declarative/graphicsitems/qdeclarativelistview.cpp index cb751f6..7c01293 100644 --- a/src/declarative/graphicsitems/qdeclarativelistview.cpp +++ b/src/declarative/graphicsitems/qdeclarativelistview.cpp @@ -744,6 +744,28 @@ void QDeclarativeListViewPrivate::refill(qreal from, qreal to, bool doBuffer) if (visibleItems.at(i)->index != -1) modelIndex = visibleItems.at(i)->index + 1; } + + if (visibleItems.count() && (fillFrom > itemEnd+averageSize+spacing + || fillTo < visiblePos - averageSize - spacing)) { + // We've jumped more than a page. Estimate which items are now + // visible and fill from there. + int count = (fillFrom - itemEnd) / (averageSize + spacing); + for (int i = 0; i < visibleItems.count(); ++i) + releaseItem(visibleItems.at(i)); + visibleItems.clear(); + modelIndex += count; + if (modelIndex >= model->count()) { + count -= modelIndex - model->count() + 1; + modelIndex = model->count() - 1; + } else if (modelIndex < 0) { + count -= modelIndex; + modelIndex = 0; + } + visibleIndex = modelIndex; + visiblePos = itemEnd + count * (averageSize + spacing) + 1; + itemEnd = visiblePos-1; + } + bool changed = false; FxListItem *item = 0; qreal pos = itemEnd + 1; diff --git a/tests/auto/declarative/qdeclarativegridview/tst_qdeclarativegridview.cpp b/tests/auto/declarative/qdeclarativegridview/tst_qdeclarativegridview.cpp index c183934..c8e7817 100644 --- a/tests/auto/declarative/qdeclarativegridview/tst_qdeclarativegridview.cpp +++ b/tests/auto/declarative/qdeclarativegridview/tst_qdeclarativegridview.cpp @@ -97,6 +97,7 @@ private slots: void onRemove_data(); void testQtQuick11Attributes(); void testQtQuick11Attributes_data(); + void contentPosJump(); private: QDeclarativeView *createView(); @@ -2077,6 +2078,56 @@ void tst_QDeclarativeGridView::testQtQuick11Attributes_data() << ""; } +void tst_QDeclarativeGridView::contentPosJump() +{ + QDeclarativeView *canvas = createView(); + + TestModel model; + for (int i = 0; i < 100; i++) + model.addItem("Item" + QString::number(i), ""); + + QDeclarativeContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + ctxt->setContextProperty("testRightToLeft", QVariant(false)); + ctxt->setContextProperty("testTopToBottom", QVariant(false)); + + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/gridview1.qml")); + qApp->processEvents(); + + QDeclarativeGridView *gridview = findItem(canvas->rootObject(), "grid"); + QVERIFY(gridview != 0); + + QDeclarativeItem *contentItem = gridview->contentItem(); + QVERIFY(contentItem != 0); + + // Test jumping more than a page of items. + gridview->setContentY(500); + + // Confirm items positioned correctly + int itemCount = findItems(contentItem, "wrapper").count(); + for (int i = 24; i < model.count() && i < itemCount; ++i) { + QDeclarativeItem *item = findItem(contentItem, "wrapper", i); + if (!item) qWarning() << "Item" << i << "not found"; + QVERIFY(item); + QVERIFY(item->x() == (i%3)*80); + QVERIFY(item->y() == (i/3)*60); + } + + gridview->setContentY(-100); + itemCount = findItems(contentItem, "wrapper").count(); + QVERIFY(itemCount < 15); + // Confirm items positioned correctly + for (int i = 0; i < model.count() && i < itemCount; ++i) { + QDeclarativeItem *item = findItem(contentItem, "wrapper", i); + if (!item) qWarning() << "Item" << i << "not found"; + QVERIFY(item); + QVERIFY(item->x() == (i%3)*80); + QVERIFY(item->y() == (i/3)*60); + } + + delete canvas; +} + QDeclarativeView *tst_QDeclarativeGridView::createView() { QDeclarativeView *canvas = new QDeclarativeView(0); diff --git a/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp b/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp index ec60e8a..0c96587 100644 --- a/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp +++ b/tests/auto/declarative/qdeclarativelistview/tst_qdeclarativelistview.cpp @@ -120,6 +120,7 @@ private slots: void rightToLeft(); void test_mirroring(); void orientationChange(); + void contentPosJump(); private: template void items(); @@ -2630,6 +2631,61 @@ void tst_QDeclarativeListView::orientationChange() delete canvas; } +void tst_QDeclarativeListView::contentPosJump() +{ + QDeclarativeView *canvas = createView(); + + TestModel model; + for (int i = 0; i < 50; i++) + model.addItem("Item" + QString::number(i), ""); + + QDeclarativeContext *ctxt = canvas->rootContext(); + ctxt->setContextProperty("testModel", &model); + + TestObject *testObject = new TestObject; + ctxt->setContextProperty("testObject", testObject); + + canvas->setSource(QUrl::fromLocalFile(SRCDIR "/data/listviewtest.qml")); + qApp->processEvents(); + + QDeclarativeListView *listview = findItem(canvas->rootObject(), "list"); + QTRY_VERIFY(listview != 0); + + QDeclarativeItem *contentItem = listview->contentItem(); + QTRY_VERIFY(contentItem != 0); + + // Confirm items positioned correctly + int itemCount = findItems(contentItem, "wrapper").count(); + for (int i = 0; i < model.count() && i < itemCount; ++i) { + QDeclarativeItem *item = findItem(contentItem, "wrapper", i); + if (!item) qWarning() << "Item" << i << "not found"; + QTRY_VERIFY(item); + QTRY_VERIFY(item->y() == i*20); + } + + // Test jumping more than a page of items. + listview->setContentY(500); + itemCount = findItems(contentItem, "wrapper").count(); + for (int i = 25; i < model.count() && i < itemCount; ++i) { + QDeclarativeItem *item = findItem(contentItem, "wrapper", i); + if (!item) qWarning() << "Item" << i << "not found"; + QTRY_VERIFY(item); + QTRY_VERIFY(item->y() == i*20); + } + + listview->setContentY(-100); + itemCount = findItems(contentItem, "wrapper").count(); + QVERIFY(itemCount < 20); + for (int i = 0; i < model.count() && i < itemCount; ++i) { + QDeclarativeItem *item = findItem(contentItem, "wrapper", i); + if (!item) qWarning() << "Item" << i << "not found"; + QTRY_VERIFY(item); + QTRY_VERIFY(item->y() == i*20); + } + + delete canvas; +} + void tst_QDeclarativeListView::qListModelInterface_items() { items(); -- cgit v0.12 From f6505f9f2eb4c594d3a249655879117e2a136468 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Thu, 14 Apr 2011 11:06:39 +1000 Subject: Add pincharea.qmlproject file for PinchArea example. Change-Id: I9d3129be4d03904805e53489c1117104e08ce860 --- .../touchinteraction/pincharea/pincharea.qmlproject | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 examples/declarative/touchinteraction/pincharea/pincharea.qmlproject diff --git a/examples/declarative/touchinteraction/pincharea/pincharea.qmlproject b/examples/declarative/touchinteraction/pincharea/pincharea.qmlproject new file mode 100644 index 0000000..e526217 --- /dev/null +++ b/examples/declarative/touchinteraction/pincharea/pincharea.qmlproject @@ -0,0 +1,18 @@ +/* File generated by QtCreator */ + +import QmlProject 1.0 + +Project { + /* Include .qml, .js, and image files from current directory and subdirectories */ + QmlFiles { + directory: "." + } + JavaScriptFiles { + directory: "." + } + ImageFiles { + directory: "." + } + /* List of plugin directories passed to QML runtime */ + // importPaths: [ " ../exampleplugin " ] +} -- cgit v0.12 From 013aa31cea9f82b53b988d910c42c5590b32c1cc Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Thu, 14 Apr 2011 13:03:31 +1000 Subject: Fix uninitialized variable. Change-Id: Ieebfc72cf9b31c9d2522487ed7cd860f060ef0be Task-number: QTBUG-15877 --- src/declarative/graphicsitems/qdeclarativegridview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/declarative/graphicsitems/qdeclarativegridview.cpp b/src/declarative/graphicsitems/qdeclarativegridview.cpp index 21bfc59..af2b804 100644 --- a/src/declarative/graphicsitems/qdeclarativegridview.cpp +++ b/src/declarative/graphicsitems/qdeclarativegridview.cpp @@ -2250,7 +2250,7 @@ qreal QDeclarativeGridView::maxXExtent() const qreal extent; qreal highlightStart; qreal highlightEnd; - qreal lastItemPosition; + qreal lastItemPosition = 0; if (d->isRightToLeftTopToBottom()){ highlightStart = d->highlightRangeStartValid ? d->highlightRangeEnd : d->size(); highlightEnd = d->highlightRangeEndValid ? d->highlightRangeStart : d->size(); -- cgit v0.12 From eac733e658422af2ceefea294023d89fc6512143 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Thu, 14 Apr 2011 14:54:35 +1000 Subject: Fix so concurrent jobs produce the correct model results Concurrent jobs sometimes modified another job's results as results were stored in member variables and modified without locks. This change removes the use of member variables for the current job, and uses QAtomicInt for the incremented job ids. (Regression from 4df66da8f9e5a9f3c981c6c60254899146dd1cc0) Task-number: QTBUG-18266 Change-Id: Ia6783e9d17603e0ff5ccd40d8cc992bdc2d3f0e9 Reviewed-by: Charles Yin --- src/declarative/util/qdeclarativexmllistmodel.cpp | 67 ++++++++++------------- 1 file changed, 28 insertions(+), 39 deletions(-) diff --git a/src/declarative/util/qdeclarativexmllistmodel.cpp b/src/declarative/util/qdeclarativexmllistmodel.cpp index c79baa4..a61ac06 100644 --- a/src/declarative/util/qdeclarativexmllistmodel.cpp +++ b/src/declarative/util/qdeclarativexmllistmodel.cpp @@ -144,6 +144,7 @@ struct XmlQueryJob QList roleQueryErrorId; // the ptr to send back if there is an error QStringList keyRoleQueries; QStringList keyRoleResultsCache; + QString prefix; }; class QDeclarativeXmlQuery : public QObject @@ -172,6 +173,12 @@ public: } int doQuery(QString query, QString namespaces, QByteArray data, QList* roleObjects, QStringList keyRoleResultsCache) { + { + QMutexLocker m1(&m_mutex); + m_queryIds.ref(); + if (m_queryIds <= 0) + m_queryIds = 1; + } XmlQueryJob job; job.queryId = m_queryIds; @@ -194,9 +201,6 @@ public: { QMutexLocker ml(&m_mutex); m_jobs.insert(m_queryIds, job); - m_queryIds++; - if (m_queryIds <= 0) - m_queryIds = 1; } QMetaObject::invokeMethod(this, "processQuery", Qt::QueuedConnection, Q_ARG(int, job.queryId)); @@ -214,20 +218,15 @@ private slots: job = m_jobs.value(queryId); } - QDeclarativeXmlQueryResult r; - doQueryJob(&job); - doSubQueryJob(&job); - r.queryId = job.queryId; - r.size = m_size; - r.data = m_modelData; - r.inserted = m_insertedItemRanges; - r.removed = m_removedItemRanges; - r.keyRoleResultsCache = job.keyRoleResultsCache; + QDeclarativeXmlQueryResult result; + result.queryId = job.queryId; + doQueryJob(&job, &result); + doSubQueryJob(&job, &result); { QMutexLocker ml(&m_mutex); if (m_jobs.contains(queryId)) { - emit queryCompleted(r); + emit queryCompleted(result); m_jobs.remove(queryId); } } @@ -241,8 +240,8 @@ protected: private: - void doQueryJob(XmlQueryJob* job); - void doSubQueryJob(XmlQueryJob* job); + void doQueryJob(XmlQueryJob *job, QDeclarativeXmlQueryResult *currentResult); + void doSubQueryJob(XmlQueryJob *job, QDeclarativeXmlQueryResult *currentResult); void getValuesOfKeyRoles(const XmlQueryJob& currentJob, QStringList *values, QXmlQuery *query) const; void addIndexToRangeList(QList *ranges, int index) const; @@ -250,17 +249,12 @@ private: QMutex m_mutex; QThread m_thread; QMap m_jobs; - int m_queryIds; - QString m_prefix; - int m_size; - QList > m_modelData; - QList m_insertedItemRanges; - QList m_removedItemRanges; + QAtomicInt m_queryIds; }; Q_GLOBAL_STATIC(QDeclarativeXmlQuery, globalXmlQuery) -void QDeclarativeXmlQuery::doQueryJob(XmlQueryJob* currentJob) +void QDeclarativeXmlQuery::doQueryJob(XmlQueryJob *currentJob, QDeclarativeXmlQueryResult *currentResult) { Q_ASSERT(currentJob->queryId != -1); @@ -295,10 +289,8 @@ void QDeclarativeXmlQuery::doQueryJob(XmlQueryJob* currentJob) } currentJob->data = xml; - m_prefix = namespaces + prefix + QLatin1Char('/'); - m_size = 0; - if (count > 0) - m_size = count; + currentJob->prefix = namespaces + prefix + QLatin1Char('/'); + currentResult->size = (count > 0 ? count : 0); } void QDeclarativeXmlQuery::getValuesOfKeyRoles(const XmlQueryJob& currentJob, QStringList *values, QXmlQuery *query) const @@ -306,9 +298,9 @@ void QDeclarativeXmlQuery::getValuesOfKeyRoles(const XmlQueryJob& currentJob, QS const QStringList &keysQueries = currentJob.keyRoleQueries; QString keysQuery; if (keysQueries.count() == 1) - keysQuery = m_prefix + keysQueries[0]; + keysQuery = currentJob.prefix + keysQueries[0]; else if (keysQueries.count() > 1) - keysQuery = m_prefix + QLatin1String("concat(") + keysQueries.join(QLatin1String(",")) + QLatin1String(")"); + keysQuery = currentJob.prefix + QLatin1String("concat(") + keysQueries.join(QLatin1String(",")) + QLatin1String(")"); if (!keysQuery.isEmpty()) { query->setQuery(keysQuery); @@ -331,10 +323,9 @@ void QDeclarativeXmlQuery::addIndexToRangeList(QList * ranges->append(qMakePair(index, 1)); } -void QDeclarativeXmlQuery::doSubQueryJob(XmlQueryJob* currentJob) +void QDeclarativeXmlQuery::doSubQueryJob(XmlQueryJob *currentJob, QDeclarativeXmlQueryResult *currentResult) { Q_ASSERT(currentJob->queryId != -1); - m_modelData.clear(); QBuffer b(¤tJob->data); b.open(QIODevice::ReadOnly); @@ -347,16 +338,14 @@ void QDeclarativeXmlQuery::doSubQueryJob(XmlQueryJob* currentJob) // See if any values of key roles have been inserted or removed. - m_insertedItemRanges.clear(); - m_removedItemRanges.clear(); if (currentJob->keyRoleResultsCache.isEmpty()) { - m_insertedItemRanges << qMakePair(0, m_size); + currentResult->inserted << qMakePair(0, currentResult->size); } else { if (keyRoleResults != currentJob->keyRoleResultsCache) { QStringList temp; for (int i=0; ikeyRoleResultsCache.count(); i++) { if (!keyRoleResults.contains(currentJob->keyRoleResultsCache[i])) - addIndexToRangeList(&m_removedItemRanges, i); + addIndexToRangeList(¤tResult->removed, i); else temp << currentJob->keyRoleResultsCache[i]; } @@ -364,12 +353,12 @@ void QDeclarativeXmlQuery::doSubQueryJob(XmlQueryJob* currentJob) for (int i=0; iinserted, i); } } } } - currentJob->keyRoleResultsCache = keyRoleResults; + currentResult->keyRoleResultsCache = keyRoleResults; // Get the new values for each role. //### we might be able to condense even further (query for everything in one go) @@ -377,7 +366,7 @@ void QDeclarativeXmlQuery::doSubQueryJob(XmlQueryJob* currentJob) for (int i = 0; i < queries.size(); ++i) { QList resultList; if (!queries[i].isEmpty()) { - subquery.setQuery(m_prefix + QLatin1String("(let $v := string(") + queries[i] + QLatin1String(") return if ($v) then ") + queries[i] + QLatin1String(" else \"\")")); + subquery.setQuery(currentJob->prefix + QLatin1String("(let $v := string(") + queries[i] + QLatin1String(") return if ($v) then ") + queries[i] + QLatin1String(" else \"\")")); if (subquery.isValid()) { QXmlResultItems resultItems; subquery.evaluateTo(&resultItems); @@ -391,9 +380,9 @@ void QDeclarativeXmlQuery::doSubQueryJob(XmlQueryJob* currentJob) } } //### should warn here if things have gone wrong. - while (resultList.count() < m_size) + while (resultList.count() < currentResult->size) resultList << QVariant(); - m_modelData << resultList; + currentResult->data << resultList; b.seek(0); } -- cgit v0.12 From d176e39de8fcde92a92866e7b0db5904c90a1e82 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 14 Apr 2011 09:05:53 +0200 Subject: Do not use SetSurfaceTransparency() on raster. When raster graphics system is forced and the HW was capable enough, we still tried to use SetSurfaceTransparency() on the RWindow to enable semi-transparency, which is wrong as it only works for windows that have a separate surface. Reviewed-by: Jani Hautakangas --- src/gui/kernel/qapplication_s60.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index f73eb02..6e70fc2 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -1855,6 +1855,8 @@ void qt_init(QApplicationPrivate * /* priv */, int) } else { QApplicationPrivate::instance()->useTranslucentEGLSurfaces = false; } + if (QApplicationPrivate::graphics_system_name == QLatin1String("raster")) + QApplicationPrivate::instance()->useTranslucentEGLSurfaces = false; #else QApplicationPrivate::instance()->useTranslucentEGLSurfaces = false; #endif -- cgit v0.12 From a5898f33f215ff2ac333be61306a47ca162b2104 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 14 Apr 2011 09:13:42 +0200 Subject: Trigger fullscreen transition effects properly on app exit. Avkon calls BeginFullScreen() and EndFullScreen() to trigger the fullscreen system transition effects for application exit, however the calls are made too late for Qt apps because the widgets are already destroyed. Instead, the effects are triggered explicitly from Qt, before closing the widgets, or from aboutToQuit, whichever comes first. Task-number: QT-4718 Reviewed-by: Jani Hautakangas --- mkspecs/common/symbian/symbian.conf | 2 +- src/gui/kernel/qapplication.cpp | 17 ++++++++++++- src/gui/kernel/qapplication_s60.cpp | 7 +++-- src/gui/kernel/qt_s60_p.h | 51 +++++++++++++++++++++++++++++++++++++ 4 files changed, 73 insertions(+), 4 deletions(-) diff --git a/mkspecs/common/symbian/symbian.conf b/mkspecs/common/symbian/symbian.conf index f955e3c..8e04099 100644 --- a/mkspecs/common/symbian/symbian.conf +++ b/mkspecs/common/symbian/symbian.conf @@ -84,7 +84,7 @@ QMAKE_LIBS_OPENGL_ES2_QT = $$QMAKE_LIBS_OPENGL_ES2 $$QMAKE_LIBS_CFBSBITMAP -lcon QMAKE_LIBS_OPENVG = $$QMAKE_LIBS_CFBSBITMAP -llibOpenVG QMAKE_LIBS_THREAD = -llibpthread QMAKE_LIBS_COMPAT = -QMAKE_LIBS_S60 = -lavkon -leikcoctl +QMAKE_LIBS_S60 = -lavkon -leikcoctl -lgfxtrans exists($${EPOCROOT}epoc32/include/platform/sgresource/sgimage.h) { QMAKE_LIBS_OPENVG += -lsgresource diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 59aec91..f906bbf 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -128,6 +128,10 @@ extern bool qt_wince_is_pocket_pc(); //qguifunctions_wince.cpp //#define ALIEN_DEBUG +#if defined(Q_OS_SYMBIAN) +#include "qt_s60_p.h" +#endif + static void initResources() { #if defined(Q_WS_WINCE) @@ -2432,6 +2436,11 @@ bool QApplication::event(QEvent *e) { Q_D(QApplication); if(e->type() == QEvent::Close) { +#if defined(Q_OS_SYMBIAN) + // In order to have proper application-exit effects on Symbian, certain + // native APIs have to be called _before_ closing/destroying the widgets. + bool effectStarted = qt_beginFullScreenEffect(); +#endif QCloseEvent *ce = static_cast(e); ce->accept(); closeAllWindows(); @@ -2445,8 +2454,14 @@ bool QApplication::event(QEvent *e) break; } } - if(ce->isAccepted()) + if (ce->isAccepted()) { return true; + } else { +#if defined(Q_OS_SYMBIAN) + if (effectStarted) + qt_abortFullScreenEffect(); +#endif + } } else if(e->type() == QEvent::LanguageChange) { #ifndef QT_NO_TRANSLATION setLayoutDirection(qt_detectRTLLanguage()?Qt::RightToLeft:Qt::LeftToRight); diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp index 6e70fc2..6620efd 100644 --- a/src/gui/kernel/qapplication_s60.cpp +++ b/src/gui/kernel/qapplication_s60.cpp @@ -1828,9 +1828,7 @@ void qt_init(QApplicationPrivate * /* priv */, int) systemFont.setFamily(systemFont.defaultFamily()); QApplicationPrivate::setSystemFont(systemFont); -#ifdef Q_SYMBIAN_TRANSITION_EFFECTS QObject::connect(qApp, SIGNAL(aboutToQuit()), qApp, SLOT(_q_aboutToQuit())); -#endif #ifdef Q_SYMBIAN_SEMITRANSPARENT_BG_SURFACE QApplicationPrivate::instance()->useTranslucentEGLSurfaces = true; @@ -1921,6 +1919,9 @@ void qt_cleanup() S60->setButtonGroupContainer(0); #endif + // Call EndFullScreen() to prevent confusing the system effect state machine. + qt_endFullScreenEffect(); + if (S60->qtOwnsS60Environment) { // Restore the S60 framework trap handler. See qt_init(). User::SetTrapHandler(S60->s60InstalledTrapHandler); @@ -2659,6 +2660,8 @@ void QApplication::restoreOverrideCursor() void QApplicationPrivate::_q_aboutToQuit() { + qt_beginFullScreenEffect(); + #ifdef Q_SYMBIAN_TRANSITION_EFFECTS // Send the shutdown tfx command S60->wsSession().SendEffectCommand(ETfxCmdAppShutDown); diff --git a/src/gui/kernel/qt_s60_p.h b/src/gui/kernel/qt_s60_p.h index e24405c..da44016 100644 --- a/src/gui/kernel/qt_s60_p.h +++ b/src/gui/kernel/qt_s60_p.h @@ -77,6 +77,8 @@ #include // CAknContextPane #include // CEikStatusPane #include // MAknFadedComponent and TAknPopupFader +#include // BeginFullScreen +#include // BeginFullScreen #endif QT_BEGIN_NAMESPACE @@ -85,6 +87,9 @@ QT_BEGIN_NAMESPACE // system events seems to start with 0x10 const TInt KInternalStatusPaneChange = 0x50000000; +// For BeginFullScreen(). +const TUint KQtAppExitFlag = 0x400; + static const int qt_symbian_max_screens = 4; //this macro exists because EColor16MAP enum value doesn't exist in Symbian OS 9.2 @@ -193,6 +198,9 @@ public: int nativeScreenWidthInPixels; int nativeScreenHeightInPixels; + + int beginFullScreenCalled : 1; + int endFullScreenCalled : 1; }; Q_AUTOTEST_EXPORT QS60Data* qGlobalS60Data(); @@ -334,6 +342,8 @@ inline QS60Data::QS60Data() #ifdef Q_OS_SYMBIAN ,s60InstalledTrapHandler(0) #endif + ,beginFullScreenCalled(0), + endFullScreenCalled(0) { } @@ -565,6 +575,47 @@ void qt_symbian_set_cursor_visible(bool visible); bool qt_symbian_is_cursor_visible(); #endif +static inline bool qt_beginFullScreenEffect() +{ +#ifdef Q_WS_S60 + // Only for post-S^3. On earlier versions the system transition effects + // may not be able to capture the non-Avkon content, leading to confusing + // looking effects, so just skip the whole thing. + if (S60->beginFullScreenCalled || QSysInfo::s60Version() <= QSysInfo::SV_S60_5_2) + return false; + S60->beginFullScreenCalled = true; + // For Avkon apps the app-exit effect is triggered from CAknAppUi::PrepareToExit(). + // That is good for Avkon apps, but in case of Qt the RWindows are destroyed earlier. + // Therefore we call BeginFullScreen() ourselves. + GfxTransEffect::BeginFullScreen(AknTransEffect::EApplicationExit, + TRect(0, 0, 0, 0), + AknTransEffect::EParameterType, + AknTransEffect::GfxTransParam(S60->uid, + AknTransEffect::TParameter::EAvkonCheck | KQtAppExitFlag)); + return true; +#endif +} + +static inline void qt_abortFullScreenEffect() +{ +#ifdef Q_WS_S60 + if (!S60->beginFullScreenCalled || QSysInfo::s60Version() <= QSysInfo::SV_S60_5_2) + return; + GfxTransEffect::AbortFullScreen(); + S60->beginFullScreenCalled = S60->endFullScreenCalled = false; +#endif +} + +static inline void qt_endFullScreenEffect() +{ +#ifdef Q_WS_S60 + if (S60->endFullScreenCalled || QSysInfo::s60Version() <= QSysInfo::SV_S60_5_2) + return; + S60->endFullScreenCalled = true; + GfxTransEffect::EndFullScreen(); +#endif +} + QT_END_NAMESPACE #endif // QT_S60_P_H -- cgit v0.12 From 25fe0f83759649af218ea7eecd849dc0a311afbc Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 14 Apr 2011 10:51:09 +0200 Subject: Fix compilation if D-Bus 1.4 isn't present. --- src/dbus/qdbusintegrator.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp index aaf19cf..d6fbe80 100644 --- a/src/dbus/qdbusintegrator.cpp +++ b/src/dbus/qdbusintegrator.cpp @@ -1682,6 +1682,9 @@ static QDBusConnection::ConnectionCapabilities connectionCapabilies(DBusConnecti return result; # endif +#ifndef DBUS_TYPE_UNIX_FD +# define DBUS_TYPE_UNIX_FD int('h') +#endif if (q_dbus_connection_can_send_type(connection, DBUS_TYPE_UNIX_FD)) result |= QDBusConnection::UnixFileDescriptorPassing; #endif -- cgit v0.12 From 0d3044b547614cbd313d90021606af1f81fb10de Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 25 Nov 2010 22:40:34 +0100 Subject: Fix strict-alias breaking warnings with GCC. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GCC doesn't like any kind of reinterpret_cast or C-style cast with pointers. So instead do the work with static_cast<>, which it seems to like. Also took the opportunity to change the generic payload type to void*, so the alignment works as expected. I wonder how we haven't had serious crashes so far on ARM... Reviewed-by: Samuel Rødal --- .../qml/qdeclarativeobjectscriptclass.cpp | 115 +++++++++++++-------- 1 file changed, 72 insertions(+), 43 deletions(-) diff --git a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp index dc3ecca..a2411b9 100644 --- a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp +++ b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp @@ -632,7 +632,6 @@ QDeclarativeObjectMethodScriptClass::property(Object *, const Identifier &name) namespace { struct MetaCallArgument { - inline MetaCallArgument(); inline ~MetaCallArgument(); inline void *dataPtr(); @@ -640,15 +639,45 @@ struct MetaCallArgument { void fromScriptValue(int type, QDeclarativeEngine *, const QScriptValue &); inline QScriptDeclarativeClass::Value toValue(QDeclarativeEngine *); +protected: + inline MetaCallArgument(); + private: MetaCallArgument(const MetaCallArgument &); + template T &as(); inline void cleanup(); - char data[4 * sizeof(void *)]; int type; bool isObjectType; + char padding[6]; // ensure sizeof(MetaCallArgument) == 8 +}; + +template struct TypedMetaCallArgument: public MetaCallArgument +{ + T data; +protected: + TypedMetaCallArgument() {} + ~TypedMetaCallArgument() {} +private: + TypedMetaCallArgument(const TypedMetaCallArgument &); }; + +struct GenericPayload { void *data[4]; }; +struct GenericMetaCallArgument: public TypedMetaCallArgument +{ +}; + +template T &MetaCallArgument::as() +{ +#ifdef Q_ALIGNOF + // static assert + char dummy_array[Q_ALIGNOF(T) <= sizeof(*this) ? 1 : -1]; Q_UNUSED(dummy_array); +#endif + TypedMetaCallArgument &typed = static_cast &>(*this); + return typed.data; +} + } MetaCallArgument::MetaCallArgument() @@ -664,22 +693,22 @@ MetaCallArgument::~MetaCallArgument() void MetaCallArgument::cleanup() { if (type == QMetaType::QString) { - ((QString *)&data)->~QString(); + as().~QString(); } else if (type == -1 || type == qMetaTypeId()) { - ((QVariant *)&data)->~QVariant(); + as().~QVariant(); } else if (type == qMetaTypeId()) { - ((QScriptValue *)&data)->~QScriptValue(); + as().~QScriptValue(); } else if (type == qMetaTypeId >()) { - ((QList *)&data)->~QList(); + as >().~QList(); } } void *MetaCallArgument::dataPtr() { if (type == -1) - return ((QVariant *)data)->data(); + return as().data(); else - return (void *)&data; + return &as(); } void MetaCallArgument::initAsType(int callType, QDeclarativeEngine *e) @@ -690,7 +719,7 @@ void MetaCallArgument::initAsType(int callType, QDeclarativeEngine *e) QScriptEngine *engine = QDeclarativeEnginePrivate::getScriptEngine(e); if (callType == qMetaTypeId()) { - new (&data) QScriptValue(engine->undefinedValue()); + new (&as()) QScriptValue(engine->undefinedValue()); type = callType; } else if (callType == QMetaType::Int || callType == QMetaType::UInt || @@ -699,20 +728,20 @@ void MetaCallArgument::initAsType(int callType, QDeclarativeEngine *e) callType == QMetaType::Float) { type = callType; } else if (callType == QMetaType::QObjectStar) { - *((QObject **)&data) = 0; + as() = 0; type = callType; } else if (callType == QMetaType::QString) { - new (&data) QString(); + new (&as()) QString(); type = callType; } else if (callType == qMetaTypeId()) { type = callType; - new (&data) QVariant(); + new (&as()) QVariant(); } else if (callType == qMetaTypeId >()) { type = callType; - new (&data) QList(); + new (&as >()) QList(); } else { type = -1; - new (&data) QVariant(callType, (void *)0); + new (&as()) QVariant(callType, (void *)0); } } @@ -721,37 +750,37 @@ void MetaCallArgument::fromScriptValue(int callType, QDeclarativeEngine *engine, if (type != 0) { cleanup(); type = 0; } if (callType == qMetaTypeId()) { - new (&data) QScriptValue(value); + new (&as()) QScriptValue(value); type = qMetaTypeId(); } else if (callType == QMetaType::Int) { - *((int *)&data) = int(value.toInt32()); + as() = int(value.toInt32()); type = callType; } else if (callType == QMetaType::UInt) { - *((uint *)&data) = uint(value.toUInt32()); + as() = uint(value.toUInt32()); type = callType; } else if (callType == QMetaType::Bool) { - *((bool *)&data) = value.toBool(); + as() = value.toBool(); type = callType; } else if (callType == QMetaType::Double) { - *((double *)&data) = double(value.toNumber()); + as() = double(value.toNumber()); type = callType; } else if (callType == QMetaType::Float) { - *((float *)&data) = float(value.toNumber()); + as() = float(value.toNumber()); type = callType; } else if (callType == QMetaType::QString) { if (value.isNull() || value.isUndefined()) - new (&data) QString(); + new (&as()) QString(); else - new (&data) QString(value.toString()); + new (&as()) QString(value.toString()); type = callType; } else if (callType == QMetaType::QObjectStar) { - *((QObject **)&data) = value.toQObject(); + as() = value.toQObject(); type = callType; } else if (callType == qMetaTypeId()) { - new (&data) QVariant(QDeclarativeEnginePrivate::get(engine)->scriptValueToVariant(value)); + new (&as()) QVariant(QDeclarativeEnginePrivate::get(engine)->scriptValueToVariant(value)); type = callType; } else if (callType == qMetaTypeId >()) { - QList *list = new (&data) QList(); + QList *list = new (&as >()) QList(); if (value.isArray()) { int length = value.property(QLatin1String("length")).toInt32(); for (int ii = 0; ii < length; ++ii) { @@ -764,16 +793,16 @@ void MetaCallArgument::fromScriptValue(int callType, QDeclarativeEngine *engine, } type = callType; } else { - new (&data) QVariant(); + new (&as()) QVariant(); type = -1; QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(engine); QVariant v = priv->scriptValueToVariant(value); if (v.userType() == callType) { - *((QVariant *)&data) = v; + as() = v; } else if (v.canConvert((QVariant::Type)callType)) { - *((QVariant *)&data) = v; - ((QVariant *)&data)->convert((QVariant::Type)callType); + as() = v; + as().convert((QVariant::Type)callType); } else if (const QMetaObject *mo = priv->rawMetaObjectForType(callType)) { QObject *obj = priv->toQObject(v); @@ -783,9 +812,9 @@ void MetaCallArgument::fromScriptValue(int callType, QDeclarativeEngine *engine, if (!objMo) obj = 0; } - *((QVariant *)&data) = QVariant(callType, &obj); + as() = QVariant(callType, &obj); } else { - *((QVariant *)&data) = QVariant(callType, (void *)0); + as() = QVariant(callType, (void *)0); } } } @@ -795,27 +824,27 @@ QScriptDeclarativeClass::Value MetaCallArgument::toValue(QDeclarativeEngine *e) QScriptEngine *engine = QDeclarativeEnginePrivate::getScriptEngine(e); if (type == qMetaTypeId()) { - return QScriptDeclarativeClass::Value(engine, *((QScriptValue *)&data)); + return QScriptDeclarativeClass::Value(engine, as()); } else if (type == QMetaType::Int) { - return QScriptDeclarativeClass::Value(engine, *((int *)&data)); + return QScriptDeclarativeClass::Value(engine, as()); } else if (type == QMetaType::UInt) { - return QScriptDeclarativeClass::Value(engine, *((uint *)&data)); + return QScriptDeclarativeClass::Value(engine, as()); } else if (type == QMetaType::Bool) { - return QScriptDeclarativeClass::Value(engine, *((bool *)&data)); + return QScriptDeclarativeClass::Value(engine, as()); } else if (type == QMetaType::Double) { - return QScriptDeclarativeClass::Value(engine, *((double *)&data)); + return QScriptDeclarativeClass::Value(engine, as()); } else if (type == QMetaType::Float) { - return QScriptDeclarativeClass::Value(engine, *((float *)&data)); + return QScriptDeclarativeClass::Value(engine, as()); } else if (type == QMetaType::QString) { - return QScriptDeclarativeClass::Value(engine, *((QString *)&data)); + return QScriptDeclarativeClass::Value(engine, as()); } else if (type == QMetaType::QObjectStar) { - QObject *object = *((QObject **)&data); + QObject *object = as(); if (object) QDeclarativeData::get(object, true)->setImplicitDestructible(); QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(e); return QScriptDeclarativeClass::Value(engine, priv->objectClass->newQObject(object)); } else if (type == qMetaTypeId >()) { - QList &list = *(QList*)&data; + QList &list = as >(); QScriptValue rv = engine->newArray(list.count()); QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(e); for (int ii = 0; ii < list.count(); ++ii) { @@ -826,7 +855,7 @@ QScriptDeclarativeClass::Value MetaCallArgument::toValue(QDeclarativeEngine *e) return QScriptDeclarativeClass::Value(engine, rv); } else if (type == -1 || type == qMetaTypeId()) { QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(e); - QScriptValue rv = ep->scriptValueFromVariant(*((QVariant *)&data)); + QScriptValue rv = ep->scriptValueFromVariant(as()); if (rv.isQObject()) { QObject *object = rv.toQObject(); if (object) @@ -906,7 +935,7 @@ QDeclarativeObjectMethodScriptClass::callMethod(QObject *object, int index, { if (argCount > 0) { - QVarLengthArray args(argCount + 1); + QVarLengthArray args(argCount + 1); args[0].initAsType(returnType, engine); for (int ii = 0; ii < argCount; ++ii) @@ -922,7 +951,7 @@ QDeclarativeObjectMethodScriptClass::callMethod(QObject *object, int index, } else if (returnType != 0) { - MetaCallArgument arg; + GenericMetaCallArgument arg; arg.initAsType(returnType, engine); void *args[] = { arg.dataPtr() }; -- cgit v0.12 From c156280a637abd6acb3894723a9e21ba2abc8fb8 Mon Sep 17 00:00:00 2001 From: Sami Merila Date: Thu, 14 Apr 2011 12:01:01 +0300 Subject: Splitview: opening a context menu should not re-position of focusItem When splitview is open and user long taps an text input item, a context menu is opened. This leads to some drawing operations on splitview implementation, even though these should be skipped. The focusItem might even be re-positioned into incorrect position due to the failure. As a fix, check if the focusItem is already positioned correctly and avoid doing anything when it already is. Task-number: QTBUG-18738 Reviewed-by: Guoqing Zhang --- src/gui/inputmethod/qcoefepinputcontext_s60.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/gui/inputmethod/qcoefepinputcontext_s60.cpp b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp index 8574f2c..b64ce0c 100644 --- a/src/gui/inputmethod/qcoefepinputcontext_s60.cpp +++ b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp @@ -538,11 +538,11 @@ void QCoeFepInputContext::ensureFocusWidgetVisible(QWidget *widget) if (alwaysResize) { windowToMove->setUpdatesEnabled(false); - if (!moveWithinVisibleArea) + if (!moveWithinVisibleArea) { m_splitViewResizeBy = widget->height(); - - windowTop = widget->geometry().top(); - widget->resize(widget->width(), splitViewRect.height() - windowTop); + windowTop = widget->geometry().top(); + widget->resize(widget->width(), splitViewRect.height() - windowTop); + } if (gv->scene()) { const QRectF microFocusRect = gv->scene()->inputMethodQuery(Qt::ImMicroFocus).toRectF(); -- cgit v0.12 From 2e7e8a2b805b868eade36cc44fa14bf8ca2f8c2f Mon Sep 17 00:00:00 2001 From: Martin Petersson Date: Thu, 14 Apr 2011 11:04:10 +0200 Subject: QNativeWifiEngine: Fix problem with wifi polling on Windows On some Windows machines the wifi detection in QNativeWifiEngine::available does not work as WlanOpenHandle still succeed altough there is no WLAN card. So instead we can detect this using the WlanEnumInterfaces in requestUpdate() instead. Task-number: QTBUG-17219 Reviewed-by: Xizhi Zhu --- src/plugins/bearer/nativewifi/qnativewifiengine.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/plugins/bearer/nativewifi/qnativewifiengine.cpp b/src/plugins/bearer/nativewifi/qnativewifiengine.cpp index 16c2239..d5beeff 100644 --- a/src/plugins/bearer/nativewifi/qnativewifiengine.cpp +++ b/src/plugins/bearer/nativewifi/qnativewifiengine.cpp @@ -501,6 +501,11 @@ void QNativeWifiEngine::requestUpdate() return; } + if (interfaceList->dwNumberOfItems == 0) { + local_WlanFreeMemory(interfaceList); + return; + } + bool requested = false; for (unsigned int i = 0; i < interfaceList->dwNumberOfItems; ++i) { result = local_WlanScan(handle, &interfaceList->InterfaceInfo[i].InterfaceGuid, 0, 0, 0); -- cgit v0.12 From 290bc1e55ee3093cadc2addfd2ea29826ee91e87 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 26 Jan 2011 14:57:34 +0100 Subject: Move the constants up, preparing for refactoring --- src/corelib/kernel/qabstracteventdispatcher.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/corelib/kernel/qabstracteventdispatcher.cpp b/src/corelib/kernel/qabstracteventdispatcher.cpp index b1b1380..06b76c9 100644 --- a/src/corelib/kernel/qabstracteventdispatcher.cpp +++ b/src/corelib/kernel/qabstracteventdispatcher.cpp @@ -49,6 +49,11 @@ QT_BEGIN_NAMESPACE // we allow for 2^24 = 8^8 = 16777216 simultaneously running timers +static const int TimerIdMask = 0x00ffffff; +static const int TimerSerialMask = ~TimerIdMask & ~0x80000000; +static const int TimerSerialCounter = TimerIdMask + 1; +static const int MaxTimerId = TimerSerialCounter - 1; + enum { NumberOfBuckets = 8, FirstBucketSize = 32 }; static const int BucketSize[NumberOfBuckets] = @@ -81,10 +86,6 @@ Q_DESTRUCTOR_FUNCTION(timerIdsDestructorFunction) static QBasicAtomicInt nextFreeTimerId = Q_BASIC_ATOMIC_INITIALIZER(1); -static const int TimerIdMask = 0x00ffffff; -static const int TimerSerialMask = ~TimerIdMask & ~0x80000000; -static const int TimerSerialCounter = TimerIdMask + 1; - // avoid the ABA-problem by using 7 of the top 8 bits of the timerId as a serial number static inline int prepareNewValueWithSerialNumber(int oldId, int newId) { -- cgit v0.12 From 050928ae69c95018718fd77084aa70fa26a033a3 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 26 Jan 2011 15:09:47 +0100 Subject: Replace the handcoded math and change the timer buckets again. Reduce from 8 to 6 buckets and increase the step between each bucket. This way, the second bucket is now of 224 timers, which should be enough for 99.9% of the applications. Also change the hardcoded math to calculations using enum values. This helps in changing the timer buckets again in the future. Also fix the last bucket not to have a timer ID of 16777216, as that is not valid. Reviewed-by: Olivier Goffart --- src/corelib/kernel/qabstracteventdispatcher.cpp | 51 +++++++++++++++++++------ 1 file changed, 40 insertions(+), 11 deletions(-) diff --git a/src/corelib/kernel/qabstracteventdispatcher.cpp b/src/corelib/kernel/qabstracteventdispatcher.cpp index 06b76c9..2949cd0 100644 --- a/src/corelib/kernel/qabstracteventdispatcher.cpp +++ b/src/corelib/kernel/qabstracteventdispatcher.cpp @@ -52,28 +52,48 @@ QT_BEGIN_NAMESPACE static const int TimerIdMask = 0x00ffffff; static const int TimerSerialMask = ~TimerIdMask & ~0x80000000; static const int TimerSerialCounter = TimerIdMask + 1; -static const int MaxTimerId = TimerSerialCounter - 1; - -enum { NumberOfBuckets = 8, FirstBucketSize = 32 }; - -static const int BucketSize[NumberOfBuckets] = - { 32, 64, 512, 4096, 32768, 262144, 2097152, 16777216 - 2364000 }; -static const int BucketOffset[NumberOfBuckets] = - { 0, 32, 96, 608, 4704, 37448, 266848, 2364000 }; +static const int MaxTimerId = TimerIdMask; static int FirstBucket[] = { 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 }; -static QBasicAtomicPointer timerIds[NumberOfBuckets] = +enum { + FirstBucketOffset = 0, + SecondBucketOffset = sizeof(FirstBucket) / sizeof(FirstBucket[0]), + ThirdBucketOffset = 0x100, + FourthBucketOffset = 0x1000, + FifthBucketOffset = 0x10000, + SixthBucketOffset = 0x100000 +}; + +enum { + FirstBucketSize = SecondBucketOffset, + SecondBucketSize = ThirdBucketOffset - SecondBucketOffset, + ThirdBucketSize = FourthBucketOffset - ThirdBucketOffset, + FourthBucketSize = FifthBucketOffset - FourthBucketOffset, + FifthBucketSize = SixthBucketOffset - FifthBucketOffset, + SixthBucketSize = MaxTimerId - SixthBucketOffset +}; + +static const int BucketSize[] = { + FirstBucketSize, SecondBucketSize, ThirdBucketSize, + FourthBucketSize, FifthBucketSize, SixthBucketSize +}; +enum { NumberOfBuckets = sizeof(BucketSize) / sizeof(BucketSize[0]) }; + +static const int BucketOffset[] = { + FirstBucketOffset, SecondBucketOffset, ThirdBucketOffset, + FourthBucketOffset, FifthBucketOffset, SixthBucketOffset +}; + +static QBasicAtomicPointer timerIds[] = { Q_BASIC_ATOMIC_INITIALIZER(FirstBucket), Q_BASIC_ATOMIC_INITIALIZER(0), Q_BASIC_ATOMIC_INITIALIZER(0), Q_BASIC_ATOMIC_INITIALIZER(0), Q_BASIC_ATOMIC_INITIALIZER(0), - Q_BASIC_ATOMIC_INITIALIZER(0), - Q_BASIC_ATOMIC_INITIALIZER(0), Q_BASIC_ATOMIC_INITIALIZER(0) }; static void timerIdsDestructorFunction() @@ -92,8 +112,17 @@ static inline int prepareNewValueWithSerialNumber(int oldId, int newId) return (newId & TimerIdMask) | ((oldId + TimerSerialCounter) & TimerSerialMask); } +namespace { + template struct QStaticAssertType; + template<> struct QStaticAssertType { enum { Value = 1 }; }; +} +#define q_static_assert(expr) (void)QStaticAssertType::Value + static inline int bucketOffset(int timerId) { + q_static_assert(sizeof BucketSize == sizeof BucketOffset); + q_static_assert(sizeof(timerIds) / sizeof(timerIds[0]) == NumberOfBuckets); + for (int i = 0; i < NumberOfBuckets; ++i) { if (timerId < BucketSize[i]) return i; -- cgit v0.12 From f4dedf1a4d7e530c715f99327da175cec67d66e4 Mon Sep 17 00:00:00 2001 From: Sami Merila Date: Thu, 14 Apr 2011 13:00:29 +0300 Subject: QGraphicsView with vertical scrollbar flickers when splitview opens Do windowstate change to fullscreen inside updateEnabled(false) - updateEnabled(true) guard block to avoid flickering of screen area, when keyboard opens in splitview. In worst case, screen is drawn three times: - resize the content area to fit into splitview - change windowstate to fullscreen - ensure visibility of the focusitem by scrolling the view Now, all these happen inside one "update". Task-number: QTBUG-18737 Reviewed-by: Guoqing Zhang --- src/gui/inputmethod/qcoefepinputcontext_s60.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/gui/inputmethod/qcoefepinputcontext_s60.cpp b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp index b64ce0c..e4b965b 100644 --- a/src/gui/inputmethod/qcoefepinputcontext_s60.cpp +++ b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp @@ -531,13 +531,15 @@ void QCoeFepInputContext::ensureFocusWidgetVisible(QWidget *widget) // and greatly reduces event passing in orientation switch cases, // as the statuspane size is not changing. + if (alwaysResize) + windowToMove->setUpdatesEnabled(false); + if (!(windowToMove->windowState() & Qt::WindowFullScreen)) { windowToMove->setWindowState( (windowToMove->windowState() & ~(Qt::WindowMinimized | Qt::WindowFullScreen)) | Qt::WindowFullScreen); } if (alwaysResize) { - windowToMove->setUpdatesEnabled(false); if (!moveWithinVisibleArea) { m_splitViewResizeBy = widget->height(); windowTop = widget->geometry().top(); @@ -548,11 +550,13 @@ void QCoeFepInputContext::ensureFocusWidgetVisible(QWidget *widget) const QRectF microFocusRect = gv->scene()->inputMethodQuery(Qt::ImMicroFocus).toRectF(); gv->ensureVisible(microFocusRect); } - windowToMove->setUpdatesEnabled(true); } else { translateInputWidget(); } + if (alwaysResize) + windowToMove->setUpdatesEnabled(true); + widget->setAttribute(Qt::WA_Resized, userResize); //not a user resize } -- cgit v0.12 From 8a37a69c961092aae7dd7f55f30a15b3fae1b7cc Mon Sep 17 00:00:00 2001 From: Sami Merila Date: Thu, 14 Apr 2011 13:22:36 +0300 Subject: Splitview flag should also be updated to inputcontext Currently splitview support is defined in exported global private method. There is no guarantee that input context is created, or updated when the API is called. This is problematic, since the client need to find a correct place and time when to call the API. As a change, update existing input context when the API is called. Also, take into account the splitview flag when updating input context. This ensures that client can enforce the flag use correctly. Task-number: QTBUG-18715 Reviewed-by: Guoqing Zhang --- src/gui/inputmethod/qcoefepinputcontext_s60.cpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/gui/inputmethod/qcoefepinputcontext_s60.cpp b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp index e4b965b..c11d5e8 100644 --- a/src/gui/inputmethod/qcoefepinputcontext_s60.cpp +++ b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp @@ -77,6 +77,15 @@ QT_BEGIN_NAMESPACE Q_GUI_EXPORT void qt_s60_setPartialScreenInputMode(bool enable) { S60->partial_keyboard = enable; + + QInputContext *ic = 0; + if (QApplication::focusWidget()) { + ic = QApplication::focusWidget()->inputContext(); + } else if (qApp && qApp->inputContext()) { + ic = qApp->inputContext(); + } + if (ic) + ic->update(); } QCoeFepInputContext::QCoeFepInputContext(QObject *parent) @@ -580,6 +589,19 @@ void QCoeFepInputContext::updateHints(bool mustUpdateInputCapabilities) QWidget *w = focusWidget(); if (w) { Qt::InputMethodHints hints = w->inputMethodHints(); + + // Since splitview support works like an input method hint, yet it is private flag, + // we need to update its state separately. + if (QSysInfo::s60Version() > QSysInfo::SV_S60_5_0) { + TInt currentFlags = m_fepState->Flags(); + if (S60->partial_keyboard) + currentFlags |= QT_EAknEditorFlagEnablePartialScreen; + else + currentFlags &= ~QT_EAknEditorFlagEnablePartialScreen; + if (currentFlags != m_fepState->Flags()) + m_fepState->SetFlags(currentFlags); + } + if (hints != m_lastImHints) { m_lastImHints = hints; applyHints(hints); -- cgit v0.12 From 94117641f97d180e0452c508fd4743bf29fb53a7 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 14 Apr 2011 12:48:25 +0200 Subject: Compile with namespace support. --- src/dbus/qdbusunixfiledescriptor.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/dbus/qdbusunixfiledescriptor.cpp b/src/dbus/qdbusunixfiledescriptor.cpp index 4817d95..f45b6cc 100644 --- a/src/dbus/qdbusunixfiledescriptor.cpp +++ b/src/dbus/qdbusunixfiledescriptor.cpp @@ -47,6 +47,8 @@ # include #endif +QT_BEGIN_NAMESPACE + /*! \class QDBusUnixFileDescriptor \inmodule QtDBus @@ -310,3 +312,5 @@ QDBusUnixFileDescriptorPrivate::~QDBusUnixFileDescriptorPrivate() } #endif + +QT_END_NAMESPACE -- cgit v0.12 From 78d47f520b2c4acdf782d39311063f5d44376913 Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Thu, 14 Apr 2011 13:08:53 +0200 Subject: QLocale: Fixed double to currency string conversion on Mac. This also fixes the autotest failure on mac with macDefaultLocale test. Reviewed-by: trustme --- src/corelib/tools/qlocale_mac.mm | 2 +- tests/auto/qlocale/tst_qlocale.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/corelib/tools/qlocale_mac.mm b/src/corelib/tools/qlocale_mac.mm index 29d9a53..52005e0 100644 --- a/src/corelib/tools/qlocale_mac.mm +++ b/src/corelib/tools/qlocale_mac.mm @@ -318,7 +318,7 @@ static QString macFormatCurrency(const QSystemLocale::CurrencyToStringArgument & break; } case QVariant::Double: { - double v = arg.value.toInt(); + double v = arg.value.toDouble(); value = CFNumberCreate(NULL, kCFNumberDoubleType, &v); break; } diff --git a/tests/auto/qlocale/tst_qlocale.cpp b/tests/auto/qlocale/tst_qlocale.cpp index cabf12e..2b7eaae 100644 --- a/tests/auto/qlocale/tst_qlocale.cpp +++ b/tests/auto/qlocale/tst_qlocale.cpp @@ -1130,10 +1130,10 @@ void tst_QLocale::macDefaultLocale() const QString timeString = locale.toString(QTime(1,2,3), QLocale::LongFormat); QVERIFY(timeString.contains(QString("1:02:03"))); - QCOMPARE(locale.toCurrencyString(qulonglong(1234)), QString("$1,234")); - QCOMPARE(locale.toCurrencyString(qlonglong(-1234)), QString("$-1,234")); + QCOMPARE(locale.toCurrencyString(qulonglong(1234)), QString("$1,234.00")); + QCOMPARE(locale.toCurrencyString(qlonglong(-1234)), QString("($1,234.00)")); QCOMPARE(locale.toCurrencyString(double(1234.56)), QString("$1,234.56")); - QCOMPARE(locale.toCurrencyString(double(-1234.56)), QString("$-1,234.56")); + QCOMPARE(locale.toCurrencyString(double(-1234.56)), QString("($1,234.56)")); // Depending on the configured time zone, the time string might not // contain a GMT specifier. (Sometimes it just names the zone, like "CEST") -- cgit v0.12 From ba172a10765bb2a5474155675485848cb730e625 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Thu, 14 Apr 2011 11:24:05 +0200 Subject: HTTP+SSL: use default SSL configuration, and avoid setting it explctly do not use a null configuration, but a default configuration in QNetworkRequest by default. In addition, setting an SSL configuration explicitly will cause the on-demand loading of root certs to be disabled (because it could be that the user has set the CA certificates explicitly). Reviewed-by: Markus Goetz --- src/network/access/qhttpthreaddelegate.cpp | 2 +- src/network/access/qnetworkrequest.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/network/access/qhttpthreaddelegate.cpp b/src/network/access/qhttpthreaddelegate.cpp index 7a17a7f..8084078 100644 --- a/src/network/access/qhttpthreaddelegate.cpp +++ b/src/network/access/qhttpthreaddelegate.cpp @@ -267,7 +267,7 @@ void QHttpThreadDelegate::startRequest() #endif #ifndef QT_NO_OPENSSL // Set the QSslConfiguration from this QNetworkRequest. - if (ssl) { + if (ssl && incomingSslConfiguration != QSslConfiguration::defaultConfiguration()) { httpConnection->setSslConfiguration(incomingSslConfiguration); } #endif diff --git a/src/network/access/qnetworkrequest.cpp b/src/network/access/qnetworkrequest.cpp index 665ee28..338969a 100644 --- a/src/network/access/qnetworkrequest.cpp +++ b/src/network/access/qnetworkrequest.cpp @@ -524,7 +524,7 @@ void QNetworkRequest::setAttribute(Attribute code, const QVariant &value) QSslConfiguration QNetworkRequest::sslConfiguration() const { if (!d->sslConfiguration) - d->sslConfiguration = new QSslConfiguration; + d->sslConfiguration = new QSslConfiguration(QSslConfiguration::defaultConfiguration()); return *d->sslConfiguration; } -- cgit v0.12 From 95154796e433b2f38b0a838a77ec1c8ae1d70c43 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Thu, 14 Apr 2011 13:45:32 +0200 Subject: L10n: German translations for Qt 4.8 --- translations/assistant_de.ts | 159 +++++++++++++++++++++++++++++++++++++------ translations/designer_de.ts | 103 ++++++++++++++++++++++++++-- translations/qt_de.ts | 22 +++++- 3 files changed, 258 insertions(+), 26 deletions(-) diff --git a/translations/assistant_de.ts b/translations/assistant_de.ts index 42557e6..c8ae518 100644 --- a/translations/assistant_de.ts +++ b/translations/assistant_de.ts @@ -261,6 +261,10 @@ Grund: Adresse + Toolbar Menu + Werkzeugleisten-Menu + + Bookmarks Menu Lesezeichen-Menü @@ -288,11 +292,11 @@ Grund: CentralWidget Add new page - Neue Seite hinzufügen + Neue Seite hinzufügen Close current page - Aktuelle Seite schließen + Aktuelle Seite schließen Print Document @@ -300,27 +304,27 @@ Grund: unknown - unbekannt + unbekannt Add New Page - Neue Seite hinzufügen + Neue Seite hinzufügen Close This Page - Aktuelle Seite schließen + Aktuelle Seite schließen Close Other Pages - Andere Seiten schließen + Andere Seiten schließen Add Bookmark for this Page... - Lesezeichen für diese Seite hinzufügen ... + Lesezeichen für diese Seite hinzufügen ... Search - Suchen + Suchen @@ -640,6 +644,49 @@ Grund: + GlobalActions + + &Back + &Rückwärts + + + &Forward + &Vorwärts + + + &Home + &Startseite + + + ALT+Home + ALT+Home + + + Zoom &in + &Vergrößern + + + Zoom &out + Ver&kleinern + + + &Copy selected Text + Ausgewählten Text &kopieren + + + &Print... + &Drucken ... + + + &Find in Text... + &Textsuche ... + + + &Find + &Suchen + + + HelpEngineWrapper Unfiltered @@ -664,16 +711,32 @@ Grund: <title>Fehler 404 ...</title><div align="center"><br><br><h1>Die Seite kann nicht gefunden werden.</h1><br><h3>'%1'</h3></div> + Open Link + Link öffnen + + Copy &Link Location &Link-Adresse kopieren + Copy + Kopieren + + + Reload + Neu laden + + Open Link in New Tab Ctrl+LMB Link in neuem Reiter öffnen (Strg + linke Maustaste) Open Link in New Tab - Link in neuem Reiter öffnen + Link in neuem Reiter öffnen + + + Open Link in New Page + Link in neuer Seite öffnen @@ -881,7 +944,7 @@ Grund: &Print... - &Drucken ... + &Drucken ... New &Tab @@ -901,15 +964,15 @@ Grund: &Copy selected Text - Ausgewählten Text &kopieren + Ausgewählten Text &kopieren &Find in Text... - &Textsuche ... + &Textsuche ... &Find - &Suchen + &Suchen Find &Next @@ -925,11 +988,11 @@ Grund: Zoom &in - &Vergrößern + &Vergrößern Zoom &out - Ver&kleinern + Ver&kleinern Normal &Size @@ -953,15 +1016,15 @@ Grund: &Home - &Startseite + &Startseite &Back - &Rückwärts + &Rückwärts &Forward - &Vorwärts + &Vorwärts Sync with Table of Contents @@ -1000,6 +1063,22 @@ Grund: Über ... + Open Pages + Offene Seiten + + + Bookmark Toolbar + Lesezeichen-Leiste + + + E&xit + B&eenden + + + ALT+P + ALT+P + + Navigation Toolbar Navigationsleiste @@ -1073,7 +1152,7 @@ Grund: ALT+Home - ALT+Home + ALT+Home &Bookmarks @@ -1089,6 +1168,17 @@ Grund: + OpenPagesWidget + + Close %1 + Schließe %1 + + + Close All Except %1 + Alle außer %1 schließen + + + OutputPage Form @@ -1307,6 +1397,14 @@ Möchten Sie sie löschen? Blank Page Leere Seite + + Appearance + Erscheinungsbild + + + Show tabs for each individual page + Reiter für jede einzelne Seite anzeigen + QCollectionGenerator @@ -1507,6 +1605,29 @@ qhelpgenerator <Hilfe-Projektdatei> [Optionen] + TabBar + + (Untitled) + (Ohne Titel) + + + New &Tab + Neuer &Reiter + + + &Close Tab + Reiter &schließen + + + Close Other Tabs + Andere Reiter schließen + + + Add Bookmark for this Page... + Lesezeichen für diese Seite hinzufügen ... + + + TopicChooser Choose a topic for <b>%1</b>: diff --git a/translations/designer_de.ts b/translations/designer_de.ts index e7aeb51..91da4c0 100644 --- a/translations/designer_de.ts +++ b/translations/designer_de.ts @@ -364,7 +364,7 @@ page - Seite + Seite Insert Page @@ -476,7 +476,7 @@ subwindow - subwindow + subwindow Subwindow @@ -520,6 +520,10 @@ Layout von '%1' von %2 in %3 umwandeln + Change layout alignment + Ausrichtung des Layouts ändern + + Add '%1' to '%2' Command description for adding buttons to a QButtonGroup '%1' zu '%2' hinzufügen @@ -1834,7 +1838,7 @@ Container-Seiten sollten ausschließlich im XML der domXML()-Methode spezifizier Edit - Bearbeiten + Bearbeiten Toolbars @@ -1849,6 +1853,10 @@ Container-Seiten sollten ausschließlich im XML der domXML()-Methode spezifizier &Ansicht + &Edit + &Bearbeiten + + &Settings &Einstellungen @@ -3734,6 +3742,10 @@ Möchten Sie sie überschreiben? Geerbt + [Theme] %1 + [Thema] %1 + + Horizontal Horizontal @@ -3742,6 +3754,10 @@ Möchten Sie sie überschreiben? Vertikal + Theme + Thema + + Normal Off Normal, aus @@ -4328,6 +4344,17 @@ Möchten Sie sie überschreiben? + qdesigner_internal::IconThemeDialog + + Set Icon From Theme + Icon aus Thema setzen + + + Input icon name from the current theme: + Icon-Name vom aktuellen Thema eingeben: + + + qdesigner_internal::ItemListEditor Properties &<< @@ -4470,15 +4497,15 @@ Möchten Sie sie überschreiben? Shortcut: - Tastenkürzel + Tastenkürzel Checkable: - Ankreuzbar: + Ankreuzbar: ToolTip: - ToolTip: + ToolTip: ... @@ -4492,6 +4519,22 @@ Möchten Sie sie überschreiben? Object &name: Objekt&name: + + T&oolTip: + T&oolTip: + + + Icon th&eme: + Icon-Th&ema: + + + &Checkable: + &Ankreuzbar: + + + &Shortcut: + Tastenk&ürzel + qdesigner_internal::NewDynamicPropertyDialog @@ -4748,9 +4791,17 @@ Please select another name. Datei auswählen... + Set Icon From Theme... + Icon aus Thema setzen... + + ... ... + + [Theme] %1 + [Thema] %1 + qdesigner_internal::PlainTextEditorDialog @@ -5132,6 +5183,42 @@ Klasse: %2 Größe + Layout Alignment + Ausrichtung des Layouts + + + No Horizontal Alignment + Keine horizontale Ausrichtung + + + Left + Links + + + Center Horizontally + Horizontal zentrieren + + + Right + Rechts + + + No Vertical Alignment + Keine vertikale Ausrichtung + + + Top + Oben + + + Center Vertically + Vertikal zentrieren + + + Bottom + Unten + + Set Minimum Width Minimalbreite festlegen @@ -5338,6 +5425,10 @@ Klasse: %2 Insert &Image &Bild einfügen + + Simplify Rich Text + Formatierbaren Text vereinfachen + qdesigner_internal::ScriptDialog diff --git a/translations/qt_de.ts b/translations/qt_de.ts index 0e62340..92a9e1d 100644 --- a/translations/qt_de.ts +++ b/translations/qt_de.ts @@ -2514,6 +2514,10 @@ nach Cannot create %1 for output %1 kann nicht erstellt werden + + No file engine available or engine does not support UnMapExtension + Es ist kein Datei-Engine verfügbar oder der gegenwärtig aktive Engine unterstützt die UnMap-Erweiterung nicht + QFileDialog @@ -3483,6 +3487,18 @@ Möchten Sie die Datei trotzdem löschen? Cannot resolve symbol "%1" in %2: %3 Das Symbol "%1" kann in %2 nicht aufgelöst werden: %3 + + '%1' is not an ELF object (%2) + '%1' ist keine ELF-Objektdatei (%2) + + + '%1' is not an ELF object + '%1' ist keine ELF-Objektdatei + + + '%1' is an invalid ELF object (%2) + '%1' ist keine gültige ELF-Objektdatei (%2) + QLineEdit @@ -3580,6 +3596,10 @@ Möchten Sie die Datei trotzdem löschen? %1: Unknown error %2 %1: Unbekannter Fehler %2 + + %1: Access denied + %1: Zugriff verweigert + QMYSQLDriver @@ -3922,7 +3942,7 @@ Möchten Sie die Datei trotzdem löschen? QNetworkAccessDataBackend Operation not supported on %1 - Diese Operation wird von %1 nicht unterstützt + Diese Operation wird von %1 nicht unterstützt Invalid URI: %1 -- cgit v0.12 From ddd633f2f4234aae353cd0239974a3a997abc71e Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Thu, 14 Apr 2011 14:08:23 +0200 Subject: QDeclarativeDebug: Don't crash when connection is closed Protocol might still be in the process of processing messages when disconnect() is called (e.g. due to an invalid package). Therefore delay it's deletion until the next event loop runs. Reviewed-by: Christiaan Janssen Task-number: QTBUG-18771 --- src/plugins/qmltooling/tcpserver/qtcpserverconnection.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/plugins/qmltooling/tcpserver/qtcpserverconnection.cpp b/src/plugins/qmltooling/tcpserver/qtcpserverconnection.cpp index 69c1ef5..7db0db3 100644 --- a/src/plugins/qmltooling/tcpserver/qtcpserverconnection.cpp +++ b/src/plugins/qmltooling/tcpserver/qtcpserverconnection.cpp @@ -97,7 +97,8 @@ void QTcpServerConnection::send(const QByteArray &message) { Q_D(QTcpServerConnection); - if (!isConnected()) + if (!isConnected() + || !d->protocol || !d->socket) return; QPacket pack; @@ -111,9 +112,10 @@ void QTcpServerConnection::disconnect() { Q_D(QTcpServerConnection); - delete d->protocol; + // protocol might still be processing packages at this point + d->protocol->deleteLater(); d->protocol = 0; - delete d->socket; + d->socket->deleteLater(); d->socket = 0; } @@ -143,6 +145,9 @@ void QTcpServerConnection::listen() void QTcpServerConnection::readyRead() { Q_D(QTcpServerConnection); + if (!d->protocol) + return; + QPacket packet = d->protocol->read(); QByteArray content = packet.data(); -- cgit v0.12 From 9ed28d039da0f3745ca84203efa92203f31e97e7 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Wed, 30 Mar 2011 14:52:21 +0200 Subject: QmlDebug: Rename 'tcpserver' library to 'qmldbg_tcp' Make the name less ambiguous, especially on Symbian were all .dlls end up in sys\bin. Reviewed-by: Pawel Polanski --- src/plugins/qmltooling/qmldbg_tcp/qmldbg_tcp.pro | 18 +++ .../qmltooling/qmldbg_tcp/qtcpserverconnection.cpp | 178 +++++++++++++++++++++ .../qmltooling/qmldbg_tcp/qtcpserverconnection.h | 84 ++++++++++ src/plugins/qmltooling/qmltooling.pro | 3 +- .../qmltooling/tcpserver/qtcpserverconnection.cpp | 178 --------------------- .../qmltooling/tcpserver/qtcpserverconnection.h | 84 ---------- src/plugins/qmltooling/tcpserver/tcpserver.pro | 18 --- tools/qml/qml.pro | 2 +- 8 files changed, 282 insertions(+), 283 deletions(-) create mode 100644 src/plugins/qmltooling/qmldbg_tcp/qmldbg_tcp.pro create mode 100644 src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp create mode 100644 src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.h delete mode 100644 src/plugins/qmltooling/tcpserver/qtcpserverconnection.cpp delete mode 100644 src/plugins/qmltooling/tcpserver/qtcpserverconnection.h delete mode 100644 src/plugins/qmltooling/tcpserver/tcpserver.pro diff --git a/src/plugins/qmltooling/qmldbg_tcp/qmldbg_tcp.pro b/src/plugins/qmltooling/qmldbg_tcp/qmldbg_tcp.pro new file mode 100644 index 0000000..e8ab962 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_tcp/qmldbg_tcp.pro @@ -0,0 +1,18 @@ +TARGET = qmldbg_tcp +QT += declarative network + +include(../../qpluginbase.pri) + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/qmltooling +QTDIR_build:REQUIRES += "contains(QT_CONFIG, declarative)" + +SOURCES += \ + qtcpserverconnection.cpp + +HEADERS += \ + qtcpserverconnection.h + +target.path += $$[QT_INSTALL_PLUGINS]/qmltooling +INSTALLS += target + +symbian:TARGET.UID3=0x20031E90 diff --git a/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp new file mode 100644 index 0000000..7db0db3 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp @@ -0,0 +1,178 @@ +/**************************************************************************** +** +** 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 QtDeclarative 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 "qtcpserverconnection.h" + +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +class QTcpServerConnectionPrivate { +public: + QTcpServerConnectionPrivate(); + + int port; + QTcpSocket *socket; + QPacketProtocol *protocol; + QTcpServer *tcpServer; + + QDeclarativeDebugServer *debugServer; +}; + +QTcpServerConnectionPrivate::QTcpServerConnectionPrivate() : + port(0), + socket(0), + protocol(0), + tcpServer(0), + debugServer(0) +{ +} + +QTcpServerConnection::QTcpServerConnection() : + d_ptr(new QTcpServerConnectionPrivate) +{ + +} + +QTcpServerConnection::~QTcpServerConnection() +{ + delete d_ptr; +} + +void QTcpServerConnection::setServer(QDeclarativeDebugServer *server) +{ + Q_D(QTcpServerConnection); + d->debugServer = server; +} + +bool QTcpServerConnection::isConnected() const +{ + Q_D(const QTcpServerConnection); + return d->socket && d->socket->state() == QTcpSocket::ConnectedState; +} + +void QTcpServerConnection::send(const QByteArray &message) +{ + Q_D(QTcpServerConnection); + + if (!isConnected() + || !d->protocol || !d->socket) + return; + + QPacket pack; + pack.writeRawData(message.data(), message.length()); + + d->protocol->send(pack); + d->socket->flush(); +} + +void QTcpServerConnection::disconnect() +{ + Q_D(QTcpServerConnection); + + // protocol might still be processing packages at this point + d->protocol->deleteLater(); + d->protocol = 0; + d->socket->deleteLater(); + d->socket = 0; +} + +void QTcpServerConnection::setPort(int port, bool block) +{ + Q_D(QTcpServerConnection); + d->port = port; + + listen(); + if (block) + d->tcpServer->waitForNewConnection(-1); +} + +void QTcpServerConnection::listen() +{ + Q_D(QTcpServerConnection); + + d->tcpServer = new QTcpServer(this); + QObject::connect(d->tcpServer, SIGNAL(newConnection()), this, SLOT(newConnection())); + if (d->tcpServer->listen(QHostAddress::Any, d->port)) + qWarning("QDeclarativeDebugServer: Waiting for connection on port %d...", d->port); + else + qWarning("QDeclarativeDebugServer: Unable to listen on port %d", d->port); +} + + +void QTcpServerConnection::readyRead() +{ + Q_D(QTcpServerConnection); + if (!d->protocol) + return; + + QPacket packet = d->protocol->read(); + + QByteArray content = packet.data(); + d->debugServer->receiveMessage(content); +} + +void QTcpServerConnection::newConnection() +{ + Q_D(QTcpServerConnection); + + if (d->socket) { + qWarning("QDeclarativeDebugServer: Another client is already connected"); + QTcpSocket *faultyConnection = d->tcpServer->nextPendingConnection(); + delete faultyConnection; + return; + } + + d->socket = d->tcpServer->nextPendingConnection(); + d->socket->setParent(this); + d->protocol = new QPacketProtocol(d->socket, this); + QObject::connect(d->protocol, SIGNAL(readyRead()), this, SLOT(readyRead())); +} + + +Q_EXPORT_PLUGIN2(tcpserver, QTcpServerConnection) + +QT_END_NAMESPACE + diff --git a/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.h b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.h new file mode 100644 index 0000000..a6e17e6 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.h @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** 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 QtDeclarative 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$ +** +****************************************************************************/ + +#ifndef QTCPSERVERCONNECTION_H +#define QTCPSERVERCONNECTION_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class QDeclarativeDebugServer; +class QTcpServerConnectionPrivate; +class QTcpServerConnection : public QObject, public QDeclarativeDebugServerConnection +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QTcpServerConnection) + Q_DISABLE_COPY(QTcpServerConnection) + Q_INTERFACES(QDeclarativeDebugServerConnection) + + +public: + QTcpServerConnection(); + ~QTcpServerConnection(); + + void setServer(QDeclarativeDebugServer *server); + void setPort(int port, bool bock); + + bool isConnected() const; + void send(const QByteArray &message); + void disconnect(); + + void listen(); + void waitForConnection(); + +private Q_SLOTS: + void readyRead(); + void newConnection(); + +private: + QTcpServerConnectionPrivate *d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QTCPSERVERCONNECTION_H diff --git a/src/plugins/qmltooling/qmltooling.pro b/src/plugins/qmltooling/qmltooling.pro index 01cf1a9..2442dc0 100644 --- a/src/plugins/qmltooling/qmltooling.pro +++ b/src/plugins/qmltooling/qmltooling.pro @@ -1,4 +1,3 @@ TEMPLATE = subdirs -SUBDIRS = tcpserver - +SUBDIRS = qmldbg_tcp diff --git a/src/plugins/qmltooling/tcpserver/qtcpserverconnection.cpp b/src/plugins/qmltooling/tcpserver/qtcpserverconnection.cpp deleted file mode 100644 index 7db0db3..0000000 --- a/src/plugins/qmltooling/tcpserver/qtcpserverconnection.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/**************************************************************************** -** -** 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 QtDeclarative 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 "qtcpserverconnection.h" - -#include -#include - -#include -#include - -QT_BEGIN_NAMESPACE - -class QTcpServerConnectionPrivate { -public: - QTcpServerConnectionPrivate(); - - int port; - QTcpSocket *socket; - QPacketProtocol *protocol; - QTcpServer *tcpServer; - - QDeclarativeDebugServer *debugServer; -}; - -QTcpServerConnectionPrivate::QTcpServerConnectionPrivate() : - port(0), - socket(0), - protocol(0), - tcpServer(0), - debugServer(0) -{ -} - -QTcpServerConnection::QTcpServerConnection() : - d_ptr(new QTcpServerConnectionPrivate) -{ - -} - -QTcpServerConnection::~QTcpServerConnection() -{ - delete d_ptr; -} - -void QTcpServerConnection::setServer(QDeclarativeDebugServer *server) -{ - Q_D(QTcpServerConnection); - d->debugServer = server; -} - -bool QTcpServerConnection::isConnected() const -{ - Q_D(const QTcpServerConnection); - return d->socket && d->socket->state() == QTcpSocket::ConnectedState; -} - -void QTcpServerConnection::send(const QByteArray &message) -{ - Q_D(QTcpServerConnection); - - if (!isConnected() - || !d->protocol || !d->socket) - return; - - QPacket pack; - pack.writeRawData(message.data(), message.length()); - - d->protocol->send(pack); - d->socket->flush(); -} - -void QTcpServerConnection::disconnect() -{ - Q_D(QTcpServerConnection); - - // protocol might still be processing packages at this point - d->protocol->deleteLater(); - d->protocol = 0; - d->socket->deleteLater(); - d->socket = 0; -} - -void QTcpServerConnection::setPort(int port, bool block) -{ - Q_D(QTcpServerConnection); - d->port = port; - - listen(); - if (block) - d->tcpServer->waitForNewConnection(-1); -} - -void QTcpServerConnection::listen() -{ - Q_D(QTcpServerConnection); - - d->tcpServer = new QTcpServer(this); - QObject::connect(d->tcpServer, SIGNAL(newConnection()), this, SLOT(newConnection())); - if (d->tcpServer->listen(QHostAddress::Any, d->port)) - qWarning("QDeclarativeDebugServer: Waiting for connection on port %d...", d->port); - else - qWarning("QDeclarativeDebugServer: Unable to listen on port %d", d->port); -} - - -void QTcpServerConnection::readyRead() -{ - Q_D(QTcpServerConnection); - if (!d->protocol) - return; - - QPacket packet = d->protocol->read(); - - QByteArray content = packet.data(); - d->debugServer->receiveMessage(content); -} - -void QTcpServerConnection::newConnection() -{ - Q_D(QTcpServerConnection); - - if (d->socket) { - qWarning("QDeclarativeDebugServer: Another client is already connected"); - QTcpSocket *faultyConnection = d->tcpServer->nextPendingConnection(); - delete faultyConnection; - return; - } - - d->socket = d->tcpServer->nextPendingConnection(); - d->socket->setParent(this); - d->protocol = new QPacketProtocol(d->socket, this); - QObject::connect(d->protocol, SIGNAL(readyRead()), this, SLOT(readyRead())); -} - - -Q_EXPORT_PLUGIN2(tcpserver, QTcpServerConnection) - -QT_END_NAMESPACE - diff --git a/src/plugins/qmltooling/tcpserver/qtcpserverconnection.h b/src/plugins/qmltooling/tcpserver/qtcpserverconnection.h deleted file mode 100644 index a6e17e6..0000000 --- a/src/plugins/qmltooling/tcpserver/qtcpserverconnection.h +++ /dev/null @@ -1,84 +0,0 @@ -/**************************************************************************** -** -** 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 QtDeclarative 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$ -** -****************************************************************************/ - -#ifndef QTCPSERVERCONNECTION_H -#define QTCPSERVERCONNECTION_H - -#include -#include - -QT_BEGIN_NAMESPACE - -class QDeclarativeDebugServer; -class QTcpServerConnectionPrivate; -class QTcpServerConnection : public QObject, public QDeclarativeDebugServerConnection -{ - Q_OBJECT - Q_DECLARE_PRIVATE(QTcpServerConnection) - Q_DISABLE_COPY(QTcpServerConnection) - Q_INTERFACES(QDeclarativeDebugServerConnection) - - -public: - QTcpServerConnection(); - ~QTcpServerConnection(); - - void setServer(QDeclarativeDebugServer *server); - void setPort(int port, bool bock); - - bool isConnected() const; - void send(const QByteArray &message); - void disconnect(); - - void listen(); - void waitForConnection(); - -private Q_SLOTS: - void readyRead(); - void newConnection(); - -private: - QTcpServerConnectionPrivate *d_ptr; -}; - -QT_END_NAMESPACE - -#endif // QTCPSERVERCONNECTION_H diff --git a/src/plugins/qmltooling/tcpserver/tcpserver.pro b/src/plugins/qmltooling/tcpserver/tcpserver.pro deleted file mode 100644 index f4f2666..0000000 --- a/src/plugins/qmltooling/tcpserver/tcpserver.pro +++ /dev/null @@ -1,18 +0,0 @@ -TARGET = tcpserver -QT += declarative network - -include(../../qpluginbase.pri) - -QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/qmltooling -QTDIR_build:REQUIRES += "contains(QT_CONFIG, declarative)" - -SOURCES += \ - qtcpserverconnection.cpp - -HEADERS += \ - qtcpserverconnection.h - -target.path += $$[QT_INSTALL_PLUGINS]/qmltooling -INSTALLS += target - -symbian:TARGET.UID3=0x20031E90 \ No newline at end of file diff --git a/tools/qml/qml.pro b/tools/qml/qml.pro index b1d56ea..bdc4b10 100644 --- a/tools/qml/qml.pro +++ b/tools/qml/qml.pro @@ -39,7 +39,7 @@ symbian { TARGET.CAPABILITY = NetworkServices ReadUserData # Deploy plugin for remote debugging - qmldebuggingplugin.sources = $$QT_BUILD_TREE/plugins/qmltooling/tcpserver$${QT_LIBINFIX}.dll + qmldebuggingplugin.sources = $$QT_BUILD_TREE/plugins/qmltooling/qmldbgtcp$${QT_LIBINFIX}.dll qmldebuggingplugin.path = c:$$QT_PLUGINS_BASE_DIR/qmltooling DEPLOYMENT += qmldebuggingplugin } -- cgit v0.12 From ead56475cc6ecd7a6e7e17d63f0e22cf930bcae4 Mon Sep 17 00:00:00 2001 From: Tom Sutcliffe Date: Wed, 23 Mar 2011 16:53:48 +0000 Subject: Adding plugin qmltooling/qmlostplugin for QML debugging over OST (USB) on Symbian. Task-number: QTBUG-18764 Reviewed-by: kkoehne --- .../debugger/qdeclarativedebugserver.cpp | 18 +- src/plugins/qmltooling/qmldbg_ost/qmldbg_ost.pro | 21 +++ src/plugins/qmltooling/qmldbg_ost/qmlostplugin.cpp | 143 +++++++++++++++ src/plugins/qmltooling/qmldbg_ost/qmlostplugin.h | 81 +++++++++ src/plugins/qmltooling/qmldbg_ost/qostdevice.cpp | 180 +++++++++++++++++++ src/plugins/qmltooling/qmldbg_ost/qostdevice.h | 75 ++++++++ src/plugins/qmltooling/qmldbg_ost/usbostcomm.h | 191 +++++++++++++++++++++ src/plugins/qmltooling/qmltooling.pro | 1 + tools/qml/qml.pro | 2 +- 9 files changed, 706 insertions(+), 6 deletions(-) create mode 100644 src/plugins/qmltooling/qmldbg_ost/qmldbg_ost.pro create mode 100644 src/plugins/qmltooling/qmldbg_ost/qmlostplugin.cpp create mode 100644 src/plugins/qmltooling/qmldbg_ost/qmlostplugin.h create mode 100644 src/plugins/qmltooling/qmldbg_ost/qostdevice.cpp create mode 100644 src/plugins/qmltooling/qmldbg_ost/qostdevice.h create mode 100644 src/plugins/qmltooling/qmldbg_ost/usbostcomm.h diff --git a/src/declarative/debugger/qdeclarativedebugserver.cpp b/src/declarative/debugger/qdeclarativedebugserver.cpp index 14e7187..18258f5 100644 --- a/src/declarative/debugger/qdeclarativedebugserver.cpp +++ b/src/declarative/debugger/qdeclarativedebugserver.cpp @@ -91,7 +91,7 @@ public: QStringList clientPlugins; bool gotHello; - static QDeclarativeDebugServerConnection *loadConnectionPlugin(); + static QDeclarativeDebugServerConnection *loadConnectionPlugin(const QString &pluginName); }; QDeclarativeDebugServerPrivate::QDeclarativeDebugServerPrivate() : @@ -113,7 +113,8 @@ void QDeclarativeDebugServerPrivate::advertisePlugins() connection->send(message); } -QDeclarativeDebugServerConnection *QDeclarativeDebugServerPrivate::loadConnectionPlugin() +QDeclarativeDebugServerConnection *QDeclarativeDebugServerPrivate::loadConnectionPlugin( + const QString &pluginName) { QStringList pluginCandidates; const QStringList paths = QCoreApplication::libraryPaths(); @@ -122,7 +123,8 @@ QDeclarativeDebugServerConnection *QDeclarativeDebugServerPrivate::loadConnectio if (dir.exists()) { QStringList plugins(dir.entryList(QDir::Files)); foreach (const QString &pluginPath, plugins) { - pluginCandidates << dir.absoluteFilePath(pluginPath); + if (QFileInfo(pluginPath).fileName().contains(pluginName)) + pluginCandidates << dir.absoluteFilePath(pluginPath); } } } @@ -166,7 +168,7 @@ QDeclarativeDebugServer *QDeclarativeDebugServer::instance() bool block = false; bool ok = false; - // format: qmljsdebugger=port:3768[,block] + // format: qmljsdebugger=port:3768[,block] OR qmljsdebugger=ost[,block] if (!appD->qmljsDebugArgumentsString().isEmpty()) { if (!QDeclarativeEnginePrivate::qml_debugging_enabled) { const QString message = @@ -177,17 +179,23 @@ QDeclarativeDebugServer *QDeclarativeDebugServer::instance() return 0; } + QString pluginName; if (appD->qmljsDebugArgumentsString().indexOf(QLatin1String("port:")) == 0) { int separatorIndex = appD->qmljsDebugArgumentsString().indexOf(QLatin1Char(',')); port = appD->qmljsDebugArgumentsString().mid(5, separatorIndex - 5).toInt(&ok); + pluginName = QLatin1String("qmldbg_tcp"); + } else if (appD->qmljsDebugArgumentsString().contains("ost")) { + pluginName = QLatin1String("qmldbg_ost"); + ok = true; } + block = appD->qmljsDebugArgumentsString().contains(QLatin1String("block")); if (ok) { server = new QDeclarativeDebugServer(); QDeclarativeDebugServerConnection *connection - = QDeclarativeDebugServerPrivate::loadConnectionPlugin(); + = QDeclarativeDebugServerPrivate::loadConnectionPlugin(pluginName); if (connection) { server->d_func()->connection = connection; diff --git a/src/plugins/qmltooling/qmldbg_ost/qmldbg_ost.pro b/src/plugins/qmltooling/qmldbg_ost/qmldbg_ost.pro new file mode 100644 index 0000000..2748889 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_ost/qmldbg_ost.pro @@ -0,0 +1,21 @@ +TARGET = qmldbg_ost +QT += declarative network + +include(../../qpluginbase.pri) + +QTDIR_build:DESTDIR = $$QT_BUILD_TREE/plugins/qmltooling +QTDIR_build:REQUIRES += "contains(QT_CONFIG, declarative)" + +SOURCES += \ + qmlostplugin.cpp \ + qostdevice.cpp + +HEADERS += \ + qmlostplugin.h \ + qostdevice.h \ + usbostcomm.h + +target.path += $$[QT_INSTALL_PLUGINS]/qmltooling +INSTALLS += target + +symbian:TARGET.UID3=0x20031E92 diff --git a/src/plugins/qmltooling/qmldbg_ost/qmlostplugin.cpp b/src/plugins/qmltooling/qmldbg_ost/qmlostplugin.cpp new file mode 100644 index 0000000..e0d7664 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_ost/qmlostplugin.cpp @@ -0,0 +1,143 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlostplugin.h" +#include "qostdevice.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +static const TInt KQmlOstProtocolId = 0x94; + +class QmlOstPluginPrivate { +public: + QmlOstPluginPrivate(); + + QOstDevice *ost; + QPacketProtocol *protocol; + QDeclarativeDebugServer *debugServer; +}; + +QmlOstPluginPrivate::QmlOstPluginPrivate() : + ost(0), + protocol(0), + debugServer(0) +{ +} + +QmlOstPlugin::QmlOstPlugin() : + d_ptr(new QmlOstPluginPrivate) +{ +} + +QmlOstPlugin::~QmlOstPlugin() +{ + delete d_ptr; +} + +void QmlOstPlugin::setServer(QDeclarativeDebugServer *server) +{ + Q_D(QmlOstPlugin); + d->debugServer = server; +} + +bool QmlOstPlugin::isConnected() const +{ + Q_D(const QmlOstPlugin); + return d->ost && d->ost->isOpen(); +} + +void QmlOstPlugin::send(const QByteArray &message) +{ + Q_D(QmlOstPlugin); + + if (!isConnected()) + return; + + QPacket pack; + pack.writeRawData(message.data(), message.length()); + + d->protocol->send(pack); + //d->socket->flush(); +} + +void QmlOstPlugin::disconnect() +{ + Q_D(QmlOstPlugin); + + delete d->protocol; + d->protocol = 0; +} + +void QmlOstPlugin::setPort(int port, bool block) +{ + Q_UNUSED(port); + Q_UNUSED(block); + + Q_D(QmlOstPlugin); + + d->ost = new QOstDevice(this); + bool ok = d->ost->open(KQmlOstProtocolId); + if (!ok) { + if (d->ost->errorString().length()) + qDebug("Error from QOstDevice: %s", qPrintable(d->ost->errorString())); + qWarning("QDeclarativeDebugServer: Unable to listen on OST"); // This message is part of the signalling - do not change the format! + return; + } + d->protocol = new QPacketProtocol(d->ost, this); + QObject::connect(d->protocol, SIGNAL(readyRead()), this, SLOT(readyRead())); + qWarning("QDeclarativeDebugServer: Waiting for connection via OST"); // This message is part of the signalling - do not change the format! +} + +void QmlOstPlugin::readyRead() +{ + Q_D(QmlOstPlugin); + QPacket packet = d->protocol->read(); + + QByteArray content = packet.data(); + d->debugServer->receiveMessage(content); +} + +Q_EXPORT_PLUGIN2(qmlostplugin, QmlOstPlugin) + +QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_ost/qmlostplugin.h b/src/plugins/qmltooling/qmldbg_ost/qmlostplugin.h new file mode 100644 index 0000000..1e18444 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_ost/qmlostplugin.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLOSTPLUGIN_H +#define QMLOSTPLUGIN_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class QDeclarativeDebugServer; +class QmlOstPluginPrivate; + +class QmlOstPlugin : public QObject, public QDeclarativeDebugServerConnection +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QmlOstPlugin) + Q_DISABLE_COPY(QmlOstPlugin) + Q_INTERFACES(QDeclarativeDebugServerConnection) + + +public: + QmlOstPlugin(); + ~QmlOstPlugin(); + + void setServer(QDeclarativeDebugServer *server); + void setPort(int port, bool bock); + + bool isConnected() const; + void send(const QByteArray &message); + void disconnect(); + +private Q_SLOTS: + void readyRead(); + +private: + QmlOstPluginPrivate *d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QMLOSTPLUGIN_H diff --git a/src/plugins/qmltooling/qmldbg_ost/qostdevice.cpp b/src/plugins/qmltooling/qmldbg_ost/qostdevice.cpp new file mode 100644 index 0000000..3c5515f --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_ost/qostdevice.cpp @@ -0,0 +1,180 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qostdevice.h" +#include + +#include "usbostcomm.h" + +class QOstDevicePrivate : public CActive +{ + QOstDevice* q_ptr; + Q_DECLARE_PUBLIC(QOstDevice) + +public: + QOstDevicePrivate() : CActive(CActive::EPriorityStandard) { + CActiveScheduler::Add(this); + } + ~QOstDevicePrivate() { + Cancel(); + } + +private: + void RunL(); + void DoCancel(); + +private: + RUsbOstComm ost; + TBuf8<4096> readBuf; + QByteArray dataBuf; +}; + +QOstDevice::QOstDevice(QObject *parent) : + QIODevice(parent), d_ptr(new QOstDevicePrivate) +{ + d_ptr->q_ptr = this; +} + +QOstDevice::~QOstDevice() +{ + close(); + delete d_ptr; +} + +bool QOstDevice::open(int ostProtocolId) +{ + if (isOpen()) + return false; + + Q_D(QOstDevice); + TInt err = d->ost.Connect(); + if (!err) err = d->ost.Open(); + const TVersion KRequiredVersion(1,1,0); + TVersion version = d->ost.Version(); + if (version.iMajor < KRequiredVersion.iMajor || + (version.iMajor == KRequiredVersion.iMajor && version.iMinor < KRequiredVersion.iMinor)) { + setErrorString("CODA version too old. At least version 4.0.18 (without TRK) is required."); + return false; + } + + if (!err) err = d->ost.RegisterProtocolID((TOstProtIds)ostProtocolId, EFalse); + if (!err) { + d->ost.ReadMessage(d->iStatus, d->readBuf); + d->SetActive(); + return QIODevice::open(ReadWrite | Unbuffered); + } + return false; +} + +void QOstDevicePrivate::RunL() +{ + Q_Q(QOstDevice); + //qDebug("QOstDevice received %d bytes q=%x", readBuf.Size(), q); + if (iStatus == KErrNone) { + QByteArray data = QByteArray::fromRawData((const char*)readBuf.Ptr(), readBuf.Size()); + dataBuf.append(data); + + readBuf.Zero(); + ost.ReadMessage(iStatus, readBuf); + SetActive(); + + emit q->readyRead(); + } else { + q->setErrorString(QString("Error %1 from RUsbOstComm::ReadMessage()").arg(iStatus.Int())); + } + //qDebug("-QOstDevicePrivate RunL"); +} + +void QOstDevicePrivate::DoCancel() +{ + ost.ReadCancel(); +} + +void QOstDevice::close() +{ + Q_D(QOstDevice); + QIODevice::close(); + d->Cancel(); + // RDbgTrcComm::Close isn't safe to call when not open, sigh + if (d->ost.Handle()) { + d->ost.Close(); + } +} + +qint64 QOstDevice::readData(char *data, qint64 maxSize) +{ + Q_D(QOstDevice); + if (d->dataBuf.length() == 0 && !d->IsActive()) + return -1; + qint64 available = qMin(maxSize, (qint64)d->dataBuf.length()); + memcpy(data, d->dataBuf.constData(), available); + d->dataBuf.remove(0, available); + return available; +} + +static const TInt KMaxOstPacketLen = 4096; + +qint64 QOstDevice::writeData(const char *data, qint64 maxSize) +{ + Q_D(QOstDevice); + TPtrC8 ptr((const TUint8*)data, (TInt)maxSize); + while (ptr.Length()) { + TPtrC8 fragment = ptr.Left(qMin(ptr.Length(), KMaxOstPacketLen)); + //qDebug("QOstDevice writing %d bytes", fragment.Length()); + TRequestStatus stat; + d->ost.WriteMessage(stat, fragment); + User::WaitForRequest(stat); + if (stat.Int() != KErrNone) { + setErrorString(QString("Error %1 from RUsbOstComm::WriteMessage()").arg(stat.Int())); + return -1; + } + ptr.Set(ptr.Mid(fragment.Length())); + } + emit bytesWritten(maxSize); //TODO does it matter this is emitted synchronously? + //qDebug("QOstDevice wrote %d bytes", ptr.Size()); + return maxSize; +} + +qint64 QOstDevice::bytesAvailable() const +{ + Q_D(const QOstDevice); + return d->dataBuf.length(); +} diff --git a/src/plugins/qmltooling/qmldbg_ost/qostdevice.h b/src/plugins/qmltooling/qmldbg_ost/qostdevice.h new file mode 100644 index 0000000..26bdc15 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_ost/qostdevice.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOSTDEVICE_H +#define QOSTDEVICE_H + +#include + +QT_BEGIN_NAMESPACE + +class QOstDevicePrivate; + +class QOstDevice : public QIODevice +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QOstDevice) + Q_DISABLE_COPY(QOstDevice) + +public: + explicit QOstDevice(QObject *parent=0); + ~QOstDevice(); + + bool open(int ostProtocolId); + void close(); + +protected: + qint64 readData(char *data, qint64 maxSize); + qint64 writeData(const char *data, qint64 maxSize); + qint64 bytesAvailable() const; + +private: + QOstDevicePrivate* d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QOSTDEVICE_H diff --git a/src/plugins/qmltooling/qmldbg_ost/usbostcomm.h b/src/plugins/qmltooling/qmldbg_ost/usbostcomm.h new file mode 100644 index 0000000..5f29e71 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_ost/usbostcomm.h @@ -0,0 +1,191 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial Usage +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef USBHOSTCOMM_H +#define USBHOSTCOMM_H + +// Based on the official usbostrouter header, modified to remove dependancy on +// the client DLL + +#include + +typedef int TOstProtIds; + +class RUsbOstComm : public RSessionBase +{ +public: + RUsbOstComm(); + TInt Connect(); + TInt Disconnect(); + TInt Open(); + TInt Close(); + TInt RegisterProtocolID(TOstProtIds aId, TBool aNeedHeader); + void ReadMessage(TRequestStatus& aStatus, TDes8& aDes); + TInt ReadCancel(); + void WriteMessage(TRequestStatus& aStatus, const TDesC8& aDes, TBool aHasHeader=EFalse); + TVersion Version() const; + +private: + enum TUsbOstCmdCode + { + EUsbOstCmdCodeFirst, + EUsbOstCmdConnect, + EUsbOstCmdDisconnect, + EUsbOstCmdCodeGetAcmConfig, + EUsbOstCmdCodeSetAcmConfig, + EUsbOstCmdCodeOpen, + EUsbOstCmdCodeClose, + EUsbOstCmdCodeRegisterId, + EUsbOstCmdCodeRegisterIds, + EUsbOstCmdCodeUnRegisterId, + EUsbOstCmdCodeUnRegisterIds, + EUsbOstCmdCodeReadMsg, + EUsbOstCmdCodeReadCancel, + EUsbOstCmdCodeWriteMsg, + EUsbOstCmdCodeWriteCancel, + EUsbOstCmdCodeLast + }; +}; + +RUsbOstComm::RUsbOstComm() +{ +} + +TInt RUsbOstComm::Connect() +{ + _LIT(KUsbOstServerName, "!UsbOstRouter"); + _LIT(KUsbOstServerImageName, "usbostrouter"); + const TUid KUsbOstServerUid = { 0x200170BE }; + TInt startupAttempts = 2; + for(;;) { + TInt ret = CreateSession(KUsbOstServerName, TVersion(1,0,0)); + if (ret != KErrNotFound && ret != KErrServerTerminated) { + return ret; + } + + if (startupAttempts-- == 0) { + return ret; + } + + RProcess server; + ret = server.Create(KUsbOstServerImageName, KNullDesC, KUsbOstServerUid); + if (ret != KErrNone) + return ret; + + TRequestStatus serverDiedRequestStatus; + server.Rendezvous(serverDiedRequestStatus); + + if (serverDiedRequestStatus != KRequestPending) { + // Abort startup + server.Kill(KErrNone); + } else { + // Logon OK - start the server + server.Resume(); + } + User::WaitForRequest(serverDiedRequestStatus); + ret = (server.ExitType() == EExitPanic) ? KErrGeneral : serverDiedRequestStatus.Int(); + server.Close(); + + if (ret != KErrNone && ret != KErrAlreadyExists) { + return ret; + } + } +} + +TInt RUsbOstComm::Disconnect() +{ + return SendReceive(EUsbOstCmdDisconnect); +} + +TInt RUsbOstComm::Open() +{ + return SendReceive(EUsbOstCmdCodeOpen); +} + +TInt RUsbOstComm::Close() +{ + TInt err = SendReceive(EUsbOstCmdCodeClose); + RHandleBase::Close(); + return err; +} + +TInt RUsbOstComm::RegisterProtocolID(const TOstProtIds aId, TBool aNeedHeader) +{ + TIpcArgs args(aId, aNeedHeader); + return SendReceive(EUsbOstCmdCodeRegisterId, args); +} + +void RUsbOstComm::ReadMessage(TRequestStatus& aStatus, TDes8& aDes) +{ + TIpcArgs args(aDes.MaxLength(), &aDes); + SendReceive(EUsbOstCmdCodeReadMsg, args, aStatus); +} + +TInt RUsbOstComm::ReadCancel() +{ + return SendReceive(EUsbOstCmdCodeReadCancel); +} + +void RUsbOstComm::WriteMessage(TRequestStatus& aStatus, const TDesC8& aDes, TBool aHasHeader) +{ + TIpcArgs args(aHasHeader, aDes.Length(), &aDes); + SendReceive(EUsbOstCmdCodeWriteMsg, args, aStatus); +} + +typedef TVersion (*TVersionFunction)(const RUsbOstComm*); +const TInt KVersionOrdinal = 17; + +TVersion RUsbOstComm::Version() const +{ + // This function has to go to the DLL, unfortunately + TVersion result; // Return 0.0.0 on any error + RLibrary lib; + TInt err = lib.Load(_L("usbostcomm")); + if (err) return result; + + TLibraryFunction fn = lib.Lookup(KVersionOrdinal); + if (fn) + result = ((TVersionFunction)fn)(this); + lib.Close(); + return result; +} + +#endif //USBHOSTCOMM_H diff --git a/src/plugins/qmltooling/qmltooling.pro b/src/plugins/qmltooling/qmltooling.pro index 2442dc0..9b3346f 100644 --- a/src/plugins/qmltooling/qmltooling.pro +++ b/src/plugins/qmltooling/qmltooling.pro @@ -1,3 +1,4 @@ TEMPLATE = subdirs SUBDIRS = qmldbg_tcp +symbian:SUBDIRS += qmldbg_ost diff --git a/tools/qml/qml.pro b/tools/qml/qml.pro index bdc4b10..84ebba8 100644 --- a/tools/qml/qml.pro +++ b/tools/qml/qml.pro @@ -39,7 +39,7 @@ symbian { TARGET.CAPABILITY = NetworkServices ReadUserData # Deploy plugin for remote debugging - qmldebuggingplugin.sources = $$QT_BUILD_TREE/plugins/qmltooling/qmldbgtcp$${QT_LIBINFIX}.dll + qmldebuggingplugin.sources = $$QT_BUILD_TREE/plugins/qmltooling/qmldbg_tcp$${QT_LIBINFIX}.dll $$QT_BUILD_TREE/plugins/qmltooling/qmldbg_ost$${QT_LIBINFIX}.dll qmldebuggingplugin.path = c:$$QT_PLUGINS_BASE_DIR/qmltooling DEPLOYMENT += qmldebuggingplugin } -- cgit v0.12 From b4b85257ccff6ba21bcbcbd46a9f7f09884abe79 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 15 Apr 2011 11:48:06 +1000 Subject: Resolve unqualified attached properties correctly When resolving unqualified attached properties, we should use the scope object, not the context object. Otherwise they will always resolve to the root object of the context, regardless of where they are written. In this example, QtObject { id: root QtObject { id: me property int a: AttachedObject.x } } the attached object should be loaded on the "me" object, not the "root" object. Change-Id: I386f886f62df7b8020c3ff703cdfc891d5739713 Reviewed-by: Martin Jones --- .../qml/qdeclarativecontextscriptclass.cpp | 16 ++++++++-------- .../data/attachedProperty.2.qml | 22 ++++++++++++++++++++++ .../declarative/qdeclarativeecmascript/testtypes.h | 5 +++-- .../tst_qdeclarativeecmascript.cpp | 10 ++++++++++ 4 files changed, 43 insertions(+), 10 deletions(-) create mode 100644 tests/auto/declarative/qdeclarativeecmascript/data/attachedProperty.2.qml diff --git a/src/declarative/qml/qdeclarativecontextscriptclass.cpp b/src/declarative/qml/qdeclarativecontextscriptclass.cpp index bb4ece4..3abd787 100644 --- a/src/declarative/qml/qdeclarativecontextscriptclass.cpp +++ b/src/declarative/qml/qdeclarativecontextscriptclass.cpp @@ -227,6 +227,7 @@ QDeclarativeContextScriptClass::queryProperty(QDeclarativeContextData *bindConte if (data) { lastData = data; lastContext = bindContext; + lastScopeObject = scopeObject; return QScriptClass::HandlesReadAccess; } } @@ -268,17 +269,12 @@ QDeclarativeContextScriptClass::property(Object *object, const Identifier &name) QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine); QScriptEngine *scriptEngine = QDeclarativeEnginePrivate::getScriptEngine(engine); - if (lastScopeObject) { - - return ep->objectClass->property(lastScopeObject, name); - - } else if (lastData) { + if (lastData) { if (lastData->type) { - return Value(scriptEngine, ep->typeNameClass->newObject(bindContext->contextObject, lastData->type)); + return Value(scriptEngine, ep->typeNameClass->newObject(lastScopeObject, lastData->type)); } else if (lastData->typeNamespace) { - return Value(scriptEngine, ep->typeNameClass->newObject(bindContext->contextObject, - lastData->typeNamespace)); + return Value(scriptEngine, ep->typeNameClass->newObject(lastScopeObject, lastData->typeNamespace)); } else { int index = lastData->importedScriptIndex; if (index < bindContext->importedScripts.count()) { @@ -288,6 +284,10 @@ QDeclarativeContextScriptClass::property(Object *object, const Identifier &name) } } + } else if (lastScopeObject) { + + return ep->objectClass->property(lastScopeObject, name); + } else if (lastPropertyIndex != -1) { QScriptValue rv; diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/attachedProperty.2.qml b/tests/auto/declarative/qdeclarativeecmascript/data/attachedProperty.2.qml new file mode 100644 index 0000000..a7184c9 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/attachedProperty.2.qml @@ -0,0 +1,22 @@ +import Qt.test 1.0 +import Qt.test 1.0 as Namespace + +MyQmlObject { + property alias a: me.a + property alias b: me.a + property alias c: me.a + property alias d: me.a + + property MyQmlObject obj + obj: MyQmlObject { + MyQmlObject.value2: 13 + + id: me + property int a: MyQmlObject.value2 * 2 + property int b: Namespace.MyQmlObject.value2 * 2 + property int c: me.Namespace.MyQmlObject.value * 2 + property int d: me.Namespace.MyQmlObject.value * 2 + } +} + + diff --git a/tests/auto/declarative/qdeclarativeecmascript/testtypes.h b/tests/auto/declarative/qdeclarativeecmascript/testtypes.h index 94cec3f..ad38d27 100644 --- a/tests/auto/declarative/qdeclarativeecmascript/testtypes.h +++ b/tests/auto/declarative/qdeclarativeecmascript/testtypes.h @@ -60,17 +60,18 @@ class MyQmlAttachedObject : public QObject { Q_OBJECT Q_PROPERTY(int value READ value CONSTANT) - Q_PROPERTY(int value2 READ value2 WRITE setValue2) + Q_PROPERTY(int value2 READ value2 WRITE setValue2 NOTIFY value2Changed) public: MyQmlAttachedObject(QObject *parent) : QObject(parent), m_value2(0) {} int value() const { return 19; } int value2() const { return m_value2; } - void setValue2(int v) { m_value2 = v; } + void setValue2(int v) { if (m_value2 == v) return; m_value2 = v; emit value2Changed(); } void emitMySignal() { emit mySignal(); } signals: + void value2Changed(); void mySignal(); private: diff --git a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp index 7876671..1ec12fe 100644 --- a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp +++ b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp @@ -650,6 +650,16 @@ void tst_qdeclarativeecmascript::attachedProperties() } { + QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.2.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + QCOMPARE(object->property("a").toInt(), 26); + QCOMPARE(object->property("b").toInt(), 26); + QCOMPARE(object->property("c").toInt(), 26); + QCOMPARE(object->property("d").toInt(), 26); + } + + { QDeclarativeComponent component(&engine, TEST_FILE("writeAttachedProperty.qml")); QObject *object = component.create(); QVERIFY(object != 0); -- cgit v0.12 From 7bc3dfc5214c6a31259d366be8e20c48195b0a50 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 15 Apr 2011 16:29:11 +1000 Subject: Fixed autotest after b4b85257ccff6ba21bcbcbd46a9f7f09884abe79 Change-Id: I7371d5c2f76254e6746d5a86874a045fc6aec32d --- tests/auto/declarative/qdeclarativeanimations/data/attached.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/declarative/qdeclarativeanimations/data/attached.qml b/tests/auto/declarative/qdeclarativeanimations/data/attached.qml index 5da4a69..c5d5535 100644 --- a/tests/auto/declarative/qdeclarativeanimations/data/attached.qml +++ b/tests/auto/declarative/qdeclarativeanimations/data/attached.qml @@ -17,7 +17,7 @@ Rectangle { transitions: Transition { PropertyAction { target: wrapper; property: "ListView.delayRemove"; value: true } - ScriptAction { script: console.log(ListView.delayRemove ? "on" : "off") } + ScriptAction { script: console.log(wrapper.ListView.delayRemove ? "on" : "off") } } Component.onCompleted: { -- cgit v0.12 From 81044282befaa5af7247804c7875df83c89c6459 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Fri, 15 Apr 2011 08:33:28 +0200 Subject: QmlDebug: Fix license headers in new ost plugin Reviewed-by: Trust-me --- src/plugins/qmltooling/qmldbg_ost/qmlostplugin.cpp | 26 +++++++++++----------- src/plugins/qmltooling/qmldbg_ost/qmlostplugin.h | 26 +++++++++++----------- src/plugins/qmltooling/qmldbg_ost/qostdevice.cpp | 26 +++++++++++----------- src/plugins/qmltooling/qmldbg_ost/qostdevice.h | 26 +++++++++++----------- src/plugins/qmltooling/qmldbg_ost/usbostcomm.h | 26 +++++++++++----------- 5 files changed, 65 insertions(+), 65 deletions(-) diff --git a/src/plugins/qmltooling/qmldbg_ost/qmlostplugin.cpp b/src/plugins/qmltooling/qmldbg_ost/qmlostplugin.cpp index e0d7664..1c91c34 100644 --- a/src/plugins/qmltooling/qmldbg_ost/qmlostplugin.cpp +++ b/src/plugins/qmltooling/qmldbg_ost/qmlostplugin.cpp @@ -7,11 +7,11 @@ ** This file is part of the QtDeclarative module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ -** Commercial Usage -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Nokia. +** 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 @@ -25,16 +25,16 @@ ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** ** $QT_END_LICENSE$ ** ****************************************************************************/ diff --git a/src/plugins/qmltooling/qmldbg_ost/qmlostplugin.h b/src/plugins/qmltooling/qmldbg_ost/qmlostplugin.h index 1e18444..eee6ee1 100644 --- a/src/plugins/qmltooling/qmldbg_ost/qmlostplugin.h +++ b/src/plugins/qmltooling/qmldbg_ost/qmlostplugin.h @@ -7,11 +7,11 @@ ** This file is part of the QtDeclarative module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ -** Commercial Usage -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Nokia. +** 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 @@ -25,16 +25,16 @@ ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** ** $QT_END_LICENSE$ ** ****************************************************************************/ diff --git a/src/plugins/qmltooling/qmldbg_ost/qostdevice.cpp b/src/plugins/qmltooling/qmldbg_ost/qostdevice.cpp index 3c5515f..21b0169 100644 --- a/src/plugins/qmltooling/qmldbg_ost/qostdevice.cpp +++ b/src/plugins/qmltooling/qmldbg_ost/qostdevice.cpp @@ -7,11 +7,11 @@ ** This file is part of the QtDeclarative module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ -** Commercial Usage -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Nokia. +** 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 @@ -25,16 +25,16 @@ ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** ** $QT_END_LICENSE$ ** ****************************************************************************/ diff --git a/src/plugins/qmltooling/qmldbg_ost/qostdevice.h b/src/plugins/qmltooling/qmldbg_ost/qostdevice.h index 26bdc15..ba1f443 100644 --- a/src/plugins/qmltooling/qmldbg_ost/qostdevice.h +++ b/src/plugins/qmltooling/qmldbg_ost/qostdevice.h @@ -7,11 +7,11 @@ ** This file is part of the QtDeclarative module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ -** Commercial Usage -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Nokia. +** 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 @@ -25,16 +25,16 @@ ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** ** $QT_END_LICENSE$ ** ****************************************************************************/ diff --git a/src/plugins/qmltooling/qmldbg_ost/usbostcomm.h b/src/plugins/qmltooling/qmldbg_ost/usbostcomm.h index 5f29e71..48ff7bf 100644 --- a/src/plugins/qmltooling/qmldbg_ost/usbostcomm.h +++ b/src/plugins/qmltooling/qmldbg_ost/usbostcomm.h @@ -7,11 +7,11 @@ ** This file is part of the QtDeclarative module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ -** Commercial Usage -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Nokia. +** 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 @@ -25,16 +25,16 @@ ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** ** $QT_END_LICENSE$ ** ****************************************************************************/ -- cgit v0.12 From 9672bec709bb8ee3d35dcd889b218708e4804c55 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Fri, 15 Apr 2011 09:05:31 +0200 Subject: Make EGL surface transparency working on Symbian. When the hardware is capable enough, setting WA_TranslucentBackground will not lead to falling back to raster, but will continue using OpenVG or OpenGL based rendering. However this needs an alpha channel which was not requested previously. This patch corrects it. Task-number: QT-4729 Reviewed-by: Jani Hautakangas --- src/gui/egl/qegl_symbian.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/gui/egl/qegl_symbian.cpp b/src/gui/egl/qegl_symbian.cpp index 6533d11..fabf9d1 100644 --- a/src/gui/egl/qegl_symbian.cpp +++ b/src/gui/egl/qegl_symbian.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include "qegl_p.h" #include "qeglcontext_p.h" @@ -73,10 +74,14 @@ void QEglProperties::setPaintDeviceFormat(QPaintDevice *dev) return; int devType = dev->devType(); - if (devType == QInternal::Image) + if (devType == QInternal::Image) { setPixelFormat(static_cast(dev)->format()); - else - setPixelFormat(QImage::Format_RGB32); + } else { + QImage::Format format = QImage::Format_RGB32; + if (QApplicationPrivate::instance() && QApplicationPrivate::instance()->useTranslucentEGLSurfaces) + format = QImage::Format_ARGB32_Premultiplied; + setPixelFormat(format); + } } -- cgit v0.12 From 56c0278fd5035d358340724c2ed9969d5332b313 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Fri, 15 Apr 2011 10:19:55 +0200 Subject: QSslConfiguration: fix equals operator --- src/network/ssl/qsslconfiguration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/ssl/qsslconfiguration.cpp b/src/network/ssl/qsslconfiguration.cpp index c8dbaed..70d7dd8 100644 --- a/src/network/ssl/qsslconfiguration.cpp +++ b/src/network/ssl/qsslconfiguration.cpp @@ -164,7 +164,7 @@ bool QSslConfiguration::operator==(const QSslConfiguration &other) const d->privateKey == other.d->privateKey && d->sessionCipher == other.d->sessionCipher && d->ciphers == other.d->ciphers && - d->caCertificates == d->caCertificates && + d->caCertificates == other.d->caCertificates && d->protocol == other.d->protocol && d->peerVerifyMode == other.d->peerVerifyMode && d->peerVerifyDepth == other.d->peerVerifyDepth; -- cgit v0.12 From dc65a73fa38d1f85b75e9d4ad71ebdbc1c7d85f5 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Fri, 15 Apr 2011 14:51:34 +0200 Subject: Build fix for transition effect support on S60 5.0. Task-number: QT-4718 Reviewed-by: TRUSTME --- src/gui/kernel/kernel.pri | 2 ++ src/gui/kernel/qt_s60_p.h | 10 +++++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri index f9c84c1..467eb9b 100644 --- a/src/gui/kernel/kernel.pri +++ b/src/gui/kernel/kernel.pri @@ -111,6 +111,8 @@ win32 { } symbian { + exists($${EPOCROOT}epoc32/include/platform/mw/akntranseffect.h): DEFINES += QT_SYMBIAN_HAVE_AKNTRANSEFFECT_H + SOURCES += \ kernel/qapplication_s60.cpp \ kernel/qeventdispatcher_s60.cpp \ diff --git a/src/gui/kernel/qt_s60_p.h b/src/gui/kernel/qt_s60_p.h index da44016..8aba53a 100644 --- a/src/gui/kernel/qt_s60_p.h +++ b/src/gui/kernel/qt_s60_p.h @@ -78,8 +78,10 @@ #include // CEikStatusPane #include // MAknFadedComponent and TAknPopupFader #include // BeginFullScreen +#ifdef QT_SYMBIAN_HAVE_AKNTRANSEFFECT_H #include // BeginFullScreen #endif +#endif QT_BEGIN_NAMESPACE @@ -577,7 +579,7 @@ bool qt_symbian_is_cursor_visible(); static inline bool qt_beginFullScreenEffect() { -#ifdef Q_WS_S60 +#if defined(Q_WS_S60) && defined(QT_SYMBIAN_HAVE_AKNTRANSEFFECT_H) // Only for post-S^3. On earlier versions the system transition effects // may not be able to capture the non-Avkon content, leading to confusing // looking effects, so just skip the whole thing. @@ -593,12 +595,14 @@ static inline bool qt_beginFullScreenEffect() AknTransEffect::GfxTransParam(S60->uid, AknTransEffect::TParameter::EAvkonCheck | KQtAppExitFlag)); return true; +#else + return false; #endif } static inline void qt_abortFullScreenEffect() { -#ifdef Q_WS_S60 +#if defined(Q_WS_S60) && defined(QT_SYMBIAN_HAVE_AKNTRANSEFFECT_H) if (!S60->beginFullScreenCalled || QSysInfo::s60Version() <= QSysInfo::SV_S60_5_2) return; GfxTransEffect::AbortFullScreen(); @@ -608,7 +612,7 @@ static inline void qt_abortFullScreenEffect() static inline void qt_endFullScreenEffect() { -#ifdef Q_WS_S60 +#if defined(Q_WS_S60) && defined(QT_SYMBIAN_HAVE_AKNTRANSEFFECT_H) if (S60->endFullScreenCalled || QSysInfo::s60Version() <= QSysInfo::SV_S60_5_2) return; S60->endFullScreenCalled = true; -- cgit v0.12 From cec6c3ad52f6b4cdf04b70340ff7d15ebd8c7d26 Mon Sep 17 00:00:00 2001 From: Carlos Manuel Duclos Vergara Date: Fri, 15 Apr 2011 16:48:27 +0200 Subject: QDesktopServices::openUrl() doesn't handle URL encodings correctly I think this is a problem with the USE_SCHEMEHANDLER version of handleUrl() in qt/src/gui/util/qdesktopservices_s60.cpp. It calls url.toString() which removes percent encoding. I think url.toEncoded() should be used instead. Task-number: QTBUG-18772 Reviewed-by: joao --- src/gui/util/qdesktopservices_s60.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/util/qdesktopservices_s60.cpp b/src/gui/util/qdesktopservices_s60.cpp index 96860df..8caeb74 100644 --- a/src/gui/util/qdesktopservices_s60.cpp +++ b/src/gui/util/qdesktopservices_s60.cpp @@ -314,7 +314,7 @@ static bool handleUrl(const QUrl &url) if (!url.isValid()) return false; - QString urlString(url.toString()); + QString urlString(url.toEncoded()); TPtrC urlPtr(qt_QString2TPtrC(urlString)); TRAPD( err, handleUrlL(urlPtr)); return err ? false : true; -- cgit v0.12 From 72032a323d2a08e414e2b09ca37b0a514e0021f2 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Sun, 17 Apr 2011 15:58:33 +0200 Subject: Do not try to test UnixFDs with the system API because it may be too old --- tests/auto/qdbustype/tst_qdbustype.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/auto/qdbustype/tst_qdbustype.cpp b/tests/auto/qdbustype/tst_qdbustype.cpp index 0469719..676a904 100644 --- a/tests/auto/qdbustype/tst_qdbustype.cpp +++ b/tests/auto/qdbustype/tst_qdbustype.cpp @@ -85,7 +85,9 @@ static void addFixedTypes() QTest::newRow("int64") << DBUS_TYPE_INT64_AS_STRING << true << true; QTest::newRow("uint64") << DBUS_TYPE_UINT64_AS_STRING << true << true; QTest::newRow("double") << DBUS_TYPE_DOUBLE_AS_STRING << true << true; - QTest::newRow("unixfd") << "h" << true << true; +#ifdef DBUS_TYPE_UNIX_FD_AS_STRING + QTest::newRow("unixfd") << DBUS_TYPE_UNIX_FD_AS_STRING << true << true; +#endif } static void addInvalidSingleLetterTypes() -- cgit v0.12 From d4fa1878ff1e7628d3e984d54f8a93810353c71b Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Sun, 17 Apr 2011 16:34:22 +0200 Subject: Fix warning about vSize not being used in this function --- src/declarative/graphicsitems/qdeclarativeflickable.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/declarative/graphicsitems/qdeclarativeflickable.cpp b/src/declarative/graphicsitems/qdeclarativeflickable.cpp index 1d50baf..3dd194b 100644 --- a/src/declarative/graphicsitems/qdeclarativeflickable.cpp +++ b/src/declarative/graphicsitems/qdeclarativeflickable.cpp @@ -266,7 +266,7 @@ void QDeclarativeFlickablePrivate::flickY(qreal velocity) flick(vData, q->minYExtent(), q->maxYExtent(), q->height(), fixupY_callback, velocity); } -void QDeclarativeFlickablePrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal vSize, +void QDeclarativeFlickablePrivate::flick(AxisData &data, qreal minExtent, qreal maxExtent, qreal, QDeclarativeTimeLineCallback::Callback fixupCallback, qreal velocity) { Q_Q(QDeclarativeFlickable); -- cgit v0.12 From fb0d4ad8f585befb58f77f8d4eaf58944448b8a7 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Mon, 18 Apr 2011 10:54:53 +0300 Subject: Add new QSysInfo::symbianVersion() enums Add new enums for future Symbian platforms and fix the docs of existing ones. Task-number: QT-4593 Reviewed-by: Sami Merila --- mkspecs/common/symbian/symbian.conf | 49 ++++++++++++++++++++----------------- src/corelib/global/qglobal.cpp | 25 +++++++++++++------ src/corelib/global/qglobal.h | 9 ++++--- 3 files changed, 50 insertions(+), 33 deletions(-) diff --git a/mkspecs/common/symbian/symbian.conf b/mkspecs/common/symbian/symbian.conf index 8e04099..0288ada 100644 --- a/mkspecs/common/symbian/symbian.conf +++ b/mkspecs/common/symbian/symbian.conf @@ -164,34 +164,39 @@ exists($${EPOCROOT}epoc32/tools/qt/mkspecs/features/environment.prf) { # Try to detect SDK version if it wasn't set by environment.prf isEmpty(SYMBIAN_VERSION)|isEmpty(S60_VERSION) { - exists($${EPOCROOT}epoc32/release/winscw/udeb/z/system/install/series60v5.3.sis)|exists($${EPOCROOT}epoc32/data/z/system/install/series60v5.3.sis) { - isEmpty(SYMBIAN_VERSION): SYMBIAN_VERSION = Symbian3 - isEmpty(S60_VERSION): S60_VERSION = 5.3 + exists($${EPOCROOT}epoc32/release/winscw/udeb/z/system/install/series60v5.4.sis)|exists($${EPOCROOT}epoc32/data/z/system/install/series60v5.4.sis) { + isEmpty(SYMBIAN_VERSION): SYMBIAN_VERSION = 5.4 + isEmpty(S60_VERSION): S60_VERSION = 5.4 } else { - # The Symbian^3 PDK does not necessarily contain the required sis files. - # However, libstdcppv5 first appeared in Symbian^3 (S60 5.2), so check for that too. - exists($${EPOCROOT}epoc32/release/winscw/udeb/z/system/install/series60v5.2.sis)|exists($${EPOCROOT}epoc32/data/z/system/install/series60v5.2.sis)|exists($${EPOCROOT}epoc32/release/armv5/lib/libstdcppv5.dso) { - isEmpty(SYMBIAN_VERSION): SYMBIAN_VERSION = Symbian3 - isEmpty(S60_VERSION): S60_VERSION = 5.2 + exists($${EPOCROOT}epoc32/release/winscw/udeb/z/system/install/series60v5.3.sis)|exists($${EPOCROOT}epoc32/data/z/system/install/series60v5.3.sis) { + isEmpty(SYMBIAN_VERSION): SYMBIAN_VERSION = 5.3 + isEmpty(S60_VERSION): S60_VERSION = 5.3 } else { - exists($${EPOCROOT}epoc32/release/winscw/udeb/z/system/install/series60v5.1.sis)|exists($${EPOCROOT}epoc32/data/z/system/install/series60v5.1.sis) { - isEmpty(SYMBIAN_VERSION): SYMBIAN_VERSION = Symbian2 - isEmpty(S60_VERSION): S60_VERSION = 5.1 + # The Symbian^3 PDK does not necessarily contain the required sis files. + # However, libstdcppv5 first appeared in Symbian^3 (S60 5.2), so check for that too. + exists($${EPOCROOT}epoc32/release/winscw/udeb/z/system/install/series60v5.2.sis)|exists($${EPOCROOT}epoc32/data/z/system/install/series60v5.2.sis)|exists($${EPOCROOT}epoc32/release/armv5/lib/libstdcppv5.dso) { + isEmpty(SYMBIAN_VERSION): SYMBIAN_VERSION = Symbian3 + isEmpty(S60_VERSION): S60_VERSION = 5.2 } else { - exists($${EPOCROOT}epoc32/release/winscw/udeb/z/system/install/series60v5.0.sis)|exists($${EPOCROOT}epoc32/data/z/system/install/series60v5.0.sis) { - isEmpty(SYMBIAN_VERSION): SYMBIAN_VERSION = 9.4 - isEmpty(S60_VERSION): S60_VERSION = 5.0 + exists($${EPOCROOT}epoc32/release/winscw/udeb/z/system/install/series60v5.1.sis)|exists($${EPOCROOT}epoc32/data/z/system/install/series60v5.1.sis) { + isEmpty(SYMBIAN_VERSION): SYMBIAN_VERSION = Symbian2 + isEmpty(S60_VERSION): S60_VERSION = 5.1 } else { - exists($${EPOCROOT}epoc32/release/winscw/udeb/z/system/install/series60v3.2.sis)|exists($${EPOCROOT}epoc32/data/z/system/install/series60v3.2.sis) { - isEmpty(SYMBIAN_VERSION): SYMBIAN_VERSION = 9.3 - isEmpty(S60_VERSION): S60_VERSION = 3.2 + exists($${EPOCROOT}epoc32/release/winscw/udeb/z/system/install/series60v5.0.sis)|exists($${EPOCROOT}epoc32/data/z/system/install/series60v5.0.sis) { + isEmpty(SYMBIAN_VERSION): SYMBIAN_VERSION = 9.4 + isEmpty(S60_VERSION): S60_VERSION = 5.0 } else { - exists($${EPOCROOT}epoc32/release/winscw/udeb/z/system/install/series60v3.1.sis)|exists($${EPOCROOT}epoc32/data/z/system/install/series60v3.1.sis) { - isEmpty(SYMBIAN_VERSION): SYMBIAN_VERSION = 9.2 - isEmpty(S60_VERSION): S60_VERSION = 3.1 + exists($${EPOCROOT}epoc32/release/winscw/udeb/z/system/install/series60v3.2.sis)|exists($${EPOCROOT}epoc32/data/z/system/install/series60v3.2.sis) { + isEmpty(SYMBIAN_VERSION): SYMBIAN_VERSION = 9.3 + isEmpty(S60_VERSION): S60_VERSION = 3.2 } else { - isEmpty(SYMBIAN_VERSION): SYMBIAN_VERSION = Unknown - isEmpty(S60_VERSION): S60_VERSION = Unknown + exists($${EPOCROOT}epoc32/release/winscw/udeb/z/system/install/series60v3.1.sis)|exists($${EPOCROOT}epoc32/data/z/system/install/series60v3.1.sis) { + isEmpty(SYMBIAN_VERSION): SYMBIAN_VERSION = 9.2 + isEmpty(S60_VERSION): S60_VERSION = 3.1 + } else { + isEmpty(SYMBIAN_VERSION): SYMBIAN_VERSION = Unknown + isEmpty(S60_VERSION): S60_VERSION = Unknown + } } } } diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index 35719b1..2cfd9cc 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -1197,10 +1197,12 @@ bool qSharedBuild() \value SV_9_2 Symbian OS v9.2 \value SV_9_3 Symbian OS v9.3 \value SV_9_4 Symbian OS v9.4 - \value SV_SF_1 Symbian^1 + \value SV_SF_1 S60 5th Edition (Symbian^1) \value SV_SF_2 Symbian^2 - \value SV_SF_3 Symbian^3 + \value SV_SF_3 Symbian^3 or Symbian Anna \value SV_SF_4 \e{This enum value is deprecated.} + \value SV_API_5_3 Symbian/S60 API version 5.3 release + \value SV_API_5_4 Symbian/S60 API version 5.4 release \value SV_Unknown An unknown and currently unsupported platform \sa S60Version, WinVersion, MacVersion @@ -1217,9 +1219,10 @@ bool qSharedBuild() \value SV_S60_3_1 S60 3rd Edition Feature Pack 1 \value SV_S60_3_2 S60 3rd Edition Feature Pack 2 \value SV_S60_5_0 S60 5th Edition - \value SV_S60_5_1 S60 5th Edition Feature Pack 1 - \value SV_S60_5_2 Symbian^3 - \value SV_S60_5_3 To be determined - FIXME + \value SV_S60_5_1 \e{This enum value is deprecated.} + \value SV_S60_5_2 Symbian^3 and Symbian Anna + \value SV_S60_5_3 Symbian/S60 API version 5.3 release + \value SV_S60_5_4 Symbian/S60 API version 5.4 release \value SV_S60_Unknown An unknown and currently unsupported platform \omitvalue SV_S60_None @@ -1852,9 +1855,12 @@ static void symbianInitVersions() } else if (minor == 2) { cachedS60Version = QSysInfo::SV_S60_5_2; cachedSymbianVersion = QSysInfo::SV_SF_3; - } else if (minor >= 3) { + } else if (minor == 3) { cachedS60Version = QSysInfo::SV_S60_5_3; - cachedSymbianVersion = QSysInfo::SV_SF_3; + cachedSymbianVersion = QSysInfo::SV_API_5_3; + } else if (minor >= 4) { + cachedS60Version = QSysInfo::SV_S60_5_4; + cachedSymbianVersion = QSysInfo::SV_API_5_4; } } } @@ -1880,7 +1886,10 @@ static void symbianInitVersions() cachedSymbianVersion = QSysInfo::SV_SF_3; # elif defined(S60_VERSION_5_3) cachedS60Version = QSysInfo::SV_S60_5_3; - cachedSymbianVersion = QSysInfo::SV_SF_3; + cachedSymbianVersion = QSysInfo::SV_API_5_3; +# elif defined(S60_VERSION_5_4) + cachedS60Version = QSysInfo::SV_S60_5_4; + cachedSymbianVersion = QSysInfo::SV_API_5_4; # endif } # endif diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 7768b46..e5109e6 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -1524,7 +1524,9 @@ public: SV_SF_1 = SV_9_4, SV_SF_2 = 40, SV_SF_3 = 50, - SV_SF_4 = 60 // Deprecated + SV_SF_4 = 60, // Deprecated + SV_API_5_3 = 70, + SV_API_5_4 = 80 }; static SymbianVersion symbianVersion(); enum S60Version { @@ -1533,9 +1535,10 @@ public: SV_S60_3_1 = SV_9_2, SV_S60_3_2 = SV_9_3, SV_S60_5_0 = SV_9_4, - SV_S60_5_1 = SV_SF_2, + SV_S60_5_1 = SV_SF_2, // Deprecated SV_S60_5_2 = SV_SF_3, - SV_S60_5_3 = 70 + SV_S60_5_3 = SV_API_5_3, + SV_S60_5_4 = SV_API_5_4 }; static S60Version s60Version(); #endif -- cgit v0.12 From 41c3b83ff68d2a58f5fda462907bbf0f8c63effc Mon Sep 17 00:00:00 2001 From: Denis Oliver Kropp Date: Mon, 18 Apr 2011 12:24:31 +0200 Subject: Fix build of Qt/DirectFB without graphics view support. Merge-request: 1187 Reviewed-by: Oswald Buddenhagen --- src/gui/widgets/qcombobox.cpp | 2 ++ src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/gui/widgets/qcombobox.cpp b/src/gui/widgets/qcombobox.cpp index 4b087e9..04ab801 100644 --- a/src/gui/widgets/qcombobox.cpp +++ b/src/gui/widgets/qcombobox.cpp @@ -704,11 +704,13 @@ void QComboBoxPrivateContainer::hideEvent(QHideEvent *) { emit resetButton(); combo->update(); +#ifndef QT_NO_GRAPHICSVIEW // QGraphicsScenePrivate::removePopup closes the combo box popup, it hides it non-explicitly. // Hiding/showing the QComboBox after this will unexpectedly show the popup as well. // Re-hiding the popup container makes sure it is explicitly hidden. if (QGraphicsProxyWidget *proxy = graphicsProxyWidget()) proxy->hide(); +#endif } void QComboBoxPrivateContainer::mousePressEvent(QMouseEvent *e) diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp index 3d8cf50..9a94c30 100644 --- a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp +++ b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp @@ -365,10 +365,12 @@ void QDirectFBWindowSurface::flush(QWidget *widget, const QRegion ®ion, if (!win) return; -#ifndef QT_NO_QWS_PROXYSCREEN +#if !defined(QT_NO_QWS_PROXYSCREEN) && !defined(QT_NO_GRAPHICSVIEW) QWExtra *extra = qt_widget_private(widget)->extraData(); if (extra && extra->proxyWidget) return; +#else + Q_UNUSED(widget); #endif const quint8 windowOpacity = quint8(win->windowOpacity() * 0xff); -- cgit v0.12 From 7c1707ba2eb8998df9713b2539564a1daa3d7e8c Mon Sep 17 00:00:00 2001 From: Sami Merila Date: Mon, 18 Apr 2011 13:46:42 +0300 Subject: Symbol table is very limited in numeric input mode Qt uses number mode keymap as a default in input context. If Special Character Table is not assigned into FEP state, the default keymap will be used. This will contain only few symbols ('*', '#', ...). As a fix, use alpha numeric keymap as a default keymap, using this will keep the symbol table same irregardless of current input mode (numbers, characters). Task-number: QT-4878 Reviewed-by: Miikka Heikkinen --- src/gui/inputmethod/qcoefepinputcontext_s60.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/inputmethod/qcoefepinputcontext_s60.cpp b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp index c11d5e8..92f8384 100644 --- a/src/gui/inputmethod/qcoefepinputcontext_s60.cpp +++ b/src/gui/inputmethod/qcoefepinputcontext_s60.cpp @@ -117,7 +117,7 @@ QCoeFepInputContext::QCoeFepInputContext(QObject *parent) m_fepState->SetDefaultCase( EAknEditorTextCase ); m_fepState->SetPermittedCases( EAknEditorAllCaseModes ); m_fepState->SetSpecialCharacterTableResourceId(R_AVKON_SPECIAL_CHARACTER_TABLE_DIALOG); - m_fepState->SetNumericKeymap( EAknEditorStandardNumberModeKeymap ); + m_fepState->SetNumericKeymap(EAknEditorAlphanumericNumberModeKeymap); } QCoeFepInputContext::~QCoeFepInputContext() -- cgit v0.12 From 9b97e319fc2a8e48a454725a5eb54edeb305a27c Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 18 Apr 2011 13:02:36 +0200 Subject: Revert "Fix strict-alias breaking warnings with GCC." This reverts commit 0d3044b547614cbd313d90021606af1f81fb10de. I'm not sure if this is good for anything. I can't reproduce the failures that happen on Mac and Windows, so let's try reverting the only patch that touches QtDeclarative. If this works, then we'll have found out that the code is broken and my patch only revealed the errors. --- .../qml/qdeclarativeobjectscriptclass.cpp | 115 ++++++++------------- 1 file changed, 43 insertions(+), 72 deletions(-) diff --git a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp index a2411b9..dc3ecca 100644 --- a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp +++ b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp @@ -632,6 +632,7 @@ QDeclarativeObjectMethodScriptClass::property(Object *, const Identifier &name) namespace { struct MetaCallArgument { + inline MetaCallArgument(); inline ~MetaCallArgument(); inline void *dataPtr(); @@ -639,45 +640,15 @@ struct MetaCallArgument { void fromScriptValue(int type, QDeclarativeEngine *, const QScriptValue &); inline QScriptDeclarativeClass::Value toValue(QDeclarativeEngine *); -protected: - inline MetaCallArgument(); - private: MetaCallArgument(const MetaCallArgument &); - template T &as(); inline void cleanup(); + char data[4 * sizeof(void *)]; int type; bool isObjectType; - char padding[6]; // ensure sizeof(MetaCallArgument) == 8 -}; - -template struct TypedMetaCallArgument: public MetaCallArgument -{ - T data; -protected: - TypedMetaCallArgument() {} - ~TypedMetaCallArgument() {} -private: - TypedMetaCallArgument(const TypedMetaCallArgument &); }; - -struct GenericPayload { void *data[4]; }; -struct GenericMetaCallArgument: public TypedMetaCallArgument -{ -}; - -template T &MetaCallArgument::as() -{ -#ifdef Q_ALIGNOF - // static assert - char dummy_array[Q_ALIGNOF(T) <= sizeof(*this) ? 1 : -1]; Q_UNUSED(dummy_array); -#endif - TypedMetaCallArgument &typed = static_cast &>(*this); - return typed.data; -} - } MetaCallArgument::MetaCallArgument() @@ -693,22 +664,22 @@ MetaCallArgument::~MetaCallArgument() void MetaCallArgument::cleanup() { if (type == QMetaType::QString) { - as().~QString(); + ((QString *)&data)->~QString(); } else if (type == -1 || type == qMetaTypeId()) { - as().~QVariant(); + ((QVariant *)&data)->~QVariant(); } else if (type == qMetaTypeId()) { - as().~QScriptValue(); + ((QScriptValue *)&data)->~QScriptValue(); } else if (type == qMetaTypeId >()) { - as >().~QList(); + ((QList *)&data)->~QList(); } } void *MetaCallArgument::dataPtr() { if (type == -1) - return as().data(); + return ((QVariant *)data)->data(); else - return &as(); + return (void *)&data; } void MetaCallArgument::initAsType(int callType, QDeclarativeEngine *e) @@ -719,7 +690,7 @@ void MetaCallArgument::initAsType(int callType, QDeclarativeEngine *e) QScriptEngine *engine = QDeclarativeEnginePrivate::getScriptEngine(e); if (callType == qMetaTypeId()) { - new (&as()) QScriptValue(engine->undefinedValue()); + new (&data) QScriptValue(engine->undefinedValue()); type = callType; } else if (callType == QMetaType::Int || callType == QMetaType::UInt || @@ -728,20 +699,20 @@ void MetaCallArgument::initAsType(int callType, QDeclarativeEngine *e) callType == QMetaType::Float) { type = callType; } else if (callType == QMetaType::QObjectStar) { - as() = 0; + *((QObject **)&data) = 0; type = callType; } else if (callType == QMetaType::QString) { - new (&as()) QString(); + new (&data) QString(); type = callType; } else if (callType == qMetaTypeId()) { type = callType; - new (&as()) QVariant(); + new (&data) QVariant(); } else if (callType == qMetaTypeId >()) { type = callType; - new (&as >()) QList(); + new (&data) QList(); } else { type = -1; - new (&as()) QVariant(callType, (void *)0); + new (&data) QVariant(callType, (void *)0); } } @@ -750,37 +721,37 @@ void MetaCallArgument::fromScriptValue(int callType, QDeclarativeEngine *engine, if (type != 0) { cleanup(); type = 0; } if (callType == qMetaTypeId()) { - new (&as()) QScriptValue(value); + new (&data) QScriptValue(value); type = qMetaTypeId(); } else if (callType == QMetaType::Int) { - as() = int(value.toInt32()); + *((int *)&data) = int(value.toInt32()); type = callType; } else if (callType == QMetaType::UInt) { - as() = uint(value.toUInt32()); + *((uint *)&data) = uint(value.toUInt32()); type = callType; } else if (callType == QMetaType::Bool) { - as() = value.toBool(); + *((bool *)&data) = value.toBool(); type = callType; } else if (callType == QMetaType::Double) { - as() = double(value.toNumber()); + *((double *)&data) = double(value.toNumber()); type = callType; } else if (callType == QMetaType::Float) { - as() = float(value.toNumber()); + *((float *)&data) = float(value.toNumber()); type = callType; } else if (callType == QMetaType::QString) { if (value.isNull() || value.isUndefined()) - new (&as()) QString(); + new (&data) QString(); else - new (&as()) QString(value.toString()); + new (&data) QString(value.toString()); type = callType; } else if (callType == QMetaType::QObjectStar) { - as() = value.toQObject(); + *((QObject **)&data) = value.toQObject(); type = callType; } else if (callType == qMetaTypeId()) { - new (&as()) QVariant(QDeclarativeEnginePrivate::get(engine)->scriptValueToVariant(value)); + new (&data) QVariant(QDeclarativeEnginePrivate::get(engine)->scriptValueToVariant(value)); type = callType; } else if (callType == qMetaTypeId >()) { - QList *list = new (&as >()) QList(); + QList *list = new (&data) QList(); if (value.isArray()) { int length = value.property(QLatin1String("length")).toInt32(); for (int ii = 0; ii < length; ++ii) { @@ -793,16 +764,16 @@ void MetaCallArgument::fromScriptValue(int callType, QDeclarativeEngine *engine, } type = callType; } else { - new (&as()) QVariant(); + new (&data) QVariant(); type = -1; QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(engine); QVariant v = priv->scriptValueToVariant(value); if (v.userType() == callType) { - as() = v; + *((QVariant *)&data) = v; } else if (v.canConvert((QVariant::Type)callType)) { - as() = v; - as().convert((QVariant::Type)callType); + *((QVariant *)&data) = v; + ((QVariant *)&data)->convert((QVariant::Type)callType); } else if (const QMetaObject *mo = priv->rawMetaObjectForType(callType)) { QObject *obj = priv->toQObject(v); @@ -812,9 +783,9 @@ void MetaCallArgument::fromScriptValue(int callType, QDeclarativeEngine *engine, if (!objMo) obj = 0; } - as() = QVariant(callType, &obj); + *((QVariant *)&data) = QVariant(callType, &obj); } else { - as() = QVariant(callType, (void *)0); + *((QVariant *)&data) = QVariant(callType, (void *)0); } } } @@ -824,27 +795,27 @@ QScriptDeclarativeClass::Value MetaCallArgument::toValue(QDeclarativeEngine *e) QScriptEngine *engine = QDeclarativeEnginePrivate::getScriptEngine(e); if (type == qMetaTypeId()) { - return QScriptDeclarativeClass::Value(engine, as()); + return QScriptDeclarativeClass::Value(engine, *((QScriptValue *)&data)); } else if (type == QMetaType::Int) { - return QScriptDeclarativeClass::Value(engine, as()); + return QScriptDeclarativeClass::Value(engine, *((int *)&data)); } else if (type == QMetaType::UInt) { - return QScriptDeclarativeClass::Value(engine, as()); + return QScriptDeclarativeClass::Value(engine, *((uint *)&data)); } else if (type == QMetaType::Bool) { - return QScriptDeclarativeClass::Value(engine, as()); + return QScriptDeclarativeClass::Value(engine, *((bool *)&data)); } else if (type == QMetaType::Double) { - return QScriptDeclarativeClass::Value(engine, as()); + return QScriptDeclarativeClass::Value(engine, *((double *)&data)); } else if (type == QMetaType::Float) { - return QScriptDeclarativeClass::Value(engine, as()); + return QScriptDeclarativeClass::Value(engine, *((float *)&data)); } else if (type == QMetaType::QString) { - return QScriptDeclarativeClass::Value(engine, as()); + return QScriptDeclarativeClass::Value(engine, *((QString *)&data)); } else if (type == QMetaType::QObjectStar) { - QObject *object = as(); + QObject *object = *((QObject **)&data); if (object) QDeclarativeData::get(object, true)->setImplicitDestructible(); QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(e); return QScriptDeclarativeClass::Value(engine, priv->objectClass->newQObject(object)); } else if (type == qMetaTypeId >()) { - QList &list = as >(); + QList &list = *(QList*)&data; QScriptValue rv = engine->newArray(list.count()); QDeclarativeEnginePrivate *priv = QDeclarativeEnginePrivate::get(e); for (int ii = 0; ii < list.count(); ++ii) { @@ -855,7 +826,7 @@ QScriptDeclarativeClass::Value MetaCallArgument::toValue(QDeclarativeEngine *e) return QScriptDeclarativeClass::Value(engine, rv); } else if (type == -1 || type == qMetaTypeId()) { QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(e); - QScriptValue rv = ep->scriptValueFromVariant(as()); + QScriptValue rv = ep->scriptValueFromVariant(*((QVariant *)&data)); if (rv.isQObject()) { QObject *object = rv.toQObject(); if (object) @@ -935,7 +906,7 @@ QDeclarativeObjectMethodScriptClass::callMethod(QObject *object, int index, { if (argCount > 0) { - QVarLengthArray args(argCount + 1); + QVarLengthArray args(argCount + 1); args[0].initAsType(returnType, engine); for (int ii = 0; ii < argCount; ++ii) @@ -951,7 +922,7 @@ QDeclarativeObjectMethodScriptClass::callMethod(QObject *object, int index, } else if (returnType != 0) { - GenericMetaCallArgument arg; + MetaCallArgument arg; arg.initAsType(returnType, engine); void *args[] = { arg.dataPtr() }; -- cgit v0.12 From 8856e2412fc2756443288644465d9edce5798fea Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Mon, 18 Apr 2011 13:15:36 +0200 Subject: Alternative fix to the strict-aliasing violation warnings The code doesn't actually violate aliasing by doing type-punned dereferencing. The objects are always accessed as the right type. So disable the warning and pray that GCC doesn't optimise code out of existence. Reviewed-by: Trust Me --- src/declarative/qml/qdeclarativeobjectscriptclass.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp index dc3ecca..9eecc65 100644 --- a/src/declarative/qml/qdeclarativeobjectscriptclass.cpp +++ b/src/declarative/qml/qdeclarativeobjectscriptclass.cpp @@ -54,7 +54,15 @@ #include #include -Q_DECLARE_METATYPE(QScriptValue); +Q_DECLARE_METATYPE(QScriptValue) + +#if defined(__GNUC__) +# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 405 +// The code in this file does not violate strict aliasing, but GCC thinks it does +// so turn off the warnings for us to have a clean build +# pragma GCC diagnostic ignored "-Wstrict-aliasing" +# endif +#endif QT_BEGIN_NAMESPACE -- cgit v0.12 From d0245f57d1b617a61bb7472c232be5b974892369 Mon Sep 17 00:00:00 2001 From: Robert Griebl Date: Mon, 18 Apr 2011 14:26:46 +0200 Subject: Use s/static/Q_GLOBAL_STATIC/g in QScroller Reviewed-by: Harald Fernengel --- src/gui/util/qscroller.cpp | 24 +++++++++++++----------- src/gui/util/qscroller_p.h | 4 ---- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/gui/util/qscroller.cpp b/src/gui/util/qscroller.cpp index 9c2d24d..db128c1 100644 --- a/src/gui/util/qscroller.cpp +++ b/src/gui/util/qscroller.cpp @@ -279,9 +279,11 @@ private: \sa QScrollEvent, QScrollPrepareEvent, QScrollerProperties */ +typedef QMap ScrollerHash; +typedef QSet ScrollerSet; -QMap QScrollerPrivate::allScrollers; -QSet QScrollerPrivate::activeScrollers; +Q_GLOBAL_STATIC(ScrollerHash, qt_allScrollers) +Q_GLOBAL_STATIC(ScrollerSet, qt_activeScrollers) /*! Returns \c true if a QScroller object was already created for \a target; \c false otherwise. @@ -290,7 +292,7 @@ QSet QScrollerPrivate::activeScrollers; */ bool QScroller::hasScroller(QObject *target) { - return (QScrollerPrivate::allScrollers.value(target)); + return (qt_allScrollers()->value(target)); } /*! @@ -308,11 +310,11 @@ QScroller *QScroller::scroller(QObject *target) return 0; } - if (QScrollerPrivate::allScrollers.contains(target)) - return QScrollerPrivate::allScrollers.value(target); + if (qt_allScrollers()->contains(target)) + return qt_allScrollers()->value(target); QScroller *s = new QScroller(target); - QScrollerPrivate::allScrollers.insert(target, s); + qt_allScrollers()->insert(target, s); return s; } @@ -332,7 +334,7 @@ const QScroller *QScroller::scroller(const QObject *target) */ QList QScroller::activeScrollers() { - return QScrollerPrivate::activeScrollers.toList(); + return qt_activeScrollers()->toList(); } /*! @@ -508,8 +510,8 @@ QScroller::~QScroller() // do not delete the recognizer. The QGestureManager is doing this. d->recognizer = 0; #endif - QScrollerPrivate::allScrollers.remove(d->target); - QScrollerPrivate::activeScrollers.remove(this); + qt_allScrollers()->remove(d->target); + qt_activeScrollers()->remove(this); delete d_ptr; } @@ -1754,9 +1756,9 @@ void QScrollerPrivate::setState(QScroller::State newstate) firstScroll = true; } if (state == QScroller::Dragging || state == QScroller::Scrolling) - activeScrollers.insert(q); + qt_activeScrollers()->insert(q); else - activeScrollers.remove(q); + qt_activeScrollers()->remove(q); emit q->stateChanged(state); } diff --git a/src/gui/util/qscroller_p.h b/src/gui/util/qscroller_p.h index 8c5f2e7..c119615 100644 --- a/src/gui/util/qscroller_p.h +++ b/src/gui/util/qscroller_p.h @@ -148,10 +148,6 @@ public slots: void targetDestroyed(); public: - // static - static QMap allScrollers; - static QSet activeScrollers; - // non static QObject *target; QScrollerProperties properties; -- cgit v0.12 From b0a01659ee47752d905b2c30bf9027ced8b1f86c Mon Sep 17 00:00:00 2001 From: Martin Petersson Date: Mon, 18 Apr 2011 14:47:55 +0200 Subject: Revert "QNativeWifiEngine: Fix problem with wifi polling on Windows" This reverts commit 2e7e8a2b805b868eade36cc44fa14bf8ca2f8c2f. This broke the QNetworkconfigurationManager auto tests. Reviewed-by: Peter Hartmann --- src/plugins/bearer/nativewifi/qnativewifiengine.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/plugins/bearer/nativewifi/qnativewifiengine.cpp b/src/plugins/bearer/nativewifi/qnativewifiengine.cpp index d5beeff..16c2239 100644 --- a/src/plugins/bearer/nativewifi/qnativewifiengine.cpp +++ b/src/plugins/bearer/nativewifi/qnativewifiengine.cpp @@ -501,11 +501,6 @@ void QNativeWifiEngine::requestUpdate() return; } - if (interfaceList->dwNumberOfItems == 0) { - local_WlanFreeMemory(interfaceList); - return; - } - bool requested = false; for (unsigned int i = 0; i < interfaceList->dwNumberOfItems; ++i) { result = local_WlanScan(handle, &interfaceList->InterfaceInfo[i].InterfaceGuid, 0, 0, 0); -- cgit v0.12 From 393462ae14f6c33d0dc462704c754cf4f6bd41c3 Mon Sep 17 00:00:00 2001 From: "Daniele E. Domenichelli" Date: Mon, 18 Apr 2011 11:21:04 -0500 Subject: QtDBus: Cleaning comments, spacing, etc. Merge-request: 2343 Reviewed-by: Marius Storm-Olsen Reviewed-by: Thiago Macieira --- src/dbus/qdbusconnection.cpp | 4 ++-- src/dbus/qdbusintegrator.cpp | 13 +++++-------- src/dbus/qdbusserver.cpp | 6 +++--- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/dbus/qdbusconnection.cpp b/src/dbus/qdbusconnection.cpp index 4883a4d..a7ee5b9 100644 --- a/src/dbus/qdbusconnection.cpp +++ b/src/dbus/qdbusconnection.cpp @@ -371,7 +371,7 @@ QDBusConnection QDBusConnection::connectToBus(BusType type, const QString &name) } /*! - Opens a peer-to-peer connection on address \a address and associate with it the + Opens a connection to a private bus on address \a address and associate with it the connection name \a name. Returns a QDBusConnection object associated with that connection. */ QDBusConnection QDBusConnection::connectToBus(const QString &address, @@ -413,7 +413,7 @@ QDBusConnection QDBusConnection::connectToBus(const QString &address, } /*! - Closes the connection of name \a name. + Closes the bus connection of name \a name. Note that if there are still QDBusConnection objects associated with the same connection, the connection will not be closed until diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp index d6fbe80..a1cb209 100644 --- a/src/dbus/qdbusintegrator.cpp +++ b/src/dbus/qdbusintegrator.cpp @@ -377,7 +377,7 @@ static void qDBusUpdateDispatchStatus(DBusConnection *connection, DBusDispatchSt static void qDBusNewConnection(DBusServer *server, DBusConnection *connection, void *data) { - // ### We may want to separate the server from the QDBusConnectionPrivate + // ### We may want to separate the server from the QDBusConnectionPrivate Q_ASSERT(server); Q_UNUSED(server); Q_ASSERT(connection); Q_ASSERT(data); @@ -385,17 +385,14 @@ static void qDBusNewConnection(DBusServer *server, DBusConnection *connection, v // keep the connection alive q_dbus_connection_ref(connection); QDBusConnectionPrivate *d = new QDBusConnectionPrivate; - - // setConnection does the error handling for us + + // setPeer does the error handling for us QDBusErrorInternal error; d->setPeer(connection, error); QDBusConnection retval = QDBusConnectionPrivate::q(d); d->setBusService(retval); - //d->name = QString::number(reinterpret_cast(d)); - //d->setConnection(d->name, d); - // make QDBusServer emit the newConnection signal QDBusConnectionPrivate *server_d = static_cast(data); server_d->serverConnection(retval); @@ -1630,7 +1627,7 @@ void QDBusConnectionPrivate::setServer(DBusServer *s, const QDBusErrorInternal & this, 0); //qDebug() << "time_functions_set" << time_functions_set; Q_UNUSED(time_functions_set); - + q_dbus_server_set_new_connection_function(server, qDBusNewConnection, this, 0); dbus_bool_t data_set = q_dbus_server_set_data(server, server_slot, this, 0); @@ -1647,7 +1644,7 @@ void QDBusConnectionPrivate::setPeer(DBusConnection *c, const QDBusErrorInternal connection = c; mode = PeerMode; - + q_dbus_connection_set_exit_on_disconnect(connection, false); q_dbus_connection_set_watch_functions(connection, qDBusAddWatch, diff --git a/src/dbus/qdbusserver.cpp b/src/dbus/qdbusserver.cpp index 9b61555..1fe80bd 100644 --- a/src/dbus/qdbusserver.cpp +++ b/src/dbus/qdbusserver.cpp @@ -74,7 +74,6 @@ QDBusServer::QDBusServer(const QString &address, QObject *parent) QObject::connect(d, SIGNAL(newServerConnection(QDBusConnection)), this, SIGNAL(newConnection(QDBusConnection))); - // server = q_dbus_server_listen( "unix:tmpdir=/tmp", &error); QDBusErrorInternal error; d->setServer(q_dbus_server_listen(address.toUtf8().constData(), error), error); } @@ -113,11 +112,12 @@ QString QDBusServer::address() const return addr; } + /*! \fn void QDBusServer::newConnection(const QDBusConnection &connection) - This signal is currently not used, but if and when it is - used, \a connection will be the new connection. + This signal is emitted when a new client connection \a connection is + established to the server. */ QT_END_NAMESPACE -- cgit v0.12 From 35a7a647faf66b281b9ca952252f90e530aa3afb Mon Sep 17 00:00:00 2001 From: "Daniele E. Domenichelli" Date: Mon, 18 Apr 2011 11:21:05 -0500 Subject: QtDBus: Fix QDBusServer to handle correctly new dbus connections Merge-request: 2343 Reviewed-by: Marius Storm-Olsen Reviewed-by: Thiago Macieira --- src/dbus/qdbusintegrator.cpp | 15 ++++++--------- src/dbus/qdbusserver.cpp | 6 ++++-- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp index a1cb209..e09b155 100644 --- a/src/dbus/qdbusintegrator.cpp +++ b/src/dbus/qdbusintegrator.cpp @@ -384,18 +384,16 @@ static void qDBusNewConnection(DBusServer *server, DBusConnection *connection, v // keep the connection alive q_dbus_connection_ref(connection); - QDBusConnectionPrivate *d = new QDBusConnectionPrivate; + QDBusConnectionPrivate *d = static_cast(data); // setPeer does the error handling for us QDBusErrorInternal error; d->setPeer(connection, error); QDBusConnection retval = QDBusConnectionPrivate::q(d); - d->setBusService(retval); // make QDBusServer emit the newConnection signal - QDBusConnectionPrivate *server_d = static_cast(data); - server_d->serverConnection(retval); + d->serverConnection(retval); } } // extern "C" @@ -1033,11 +1031,10 @@ void QDBusConnectionPrivate::closeConnection() mode = InvalidMode; // prevent reentrancy baseService.clear(); - if (oldMode == ServerMode) { - if (server) { - q_dbus_server_disconnect(server); - } - } else if (oldMode == ClientMode || oldMode == PeerMode) { + if (server) + q_dbus_server_disconnect(server); + + if (oldMode == ClientMode || oldMode == PeerMode) { if (connection) { q_dbus_connection_close(connection); // send the "close" message diff --git a/src/dbus/qdbusserver.cpp b/src/dbus/qdbusserver.cpp index 1fe80bd..3189b4e 100644 --- a/src/dbus/qdbusserver.cpp +++ b/src/dbus/qdbusserver.cpp @@ -62,14 +62,16 @@ QT_BEGIN_NAMESPACE QDBusServer::QDBusServer(const QString &address, QObject *parent) : QObject(parent) { + if (address.isEmpty()) + return; + if (!qdbus_loadLibDBus()) { d = 0; return; } d = new QDBusConnectionPrivate(this); - if (address.isEmpty()) - return; + d->name = QLatin1String("QDBusServer-") + QString::number(reinterpret_cast(d)); QObject::connect(d, SIGNAL(newServerConnection(QDBusConnection)), this, SIGNAL(newConnection(QDBusConnection))); -- cgit v0.12 From bc0bf6f84034267d1e15ca9ca31e6498e6d97bd3 Mon Sep 17 00:00:00 2001 From: "Daniele E. Domenichelli" Date: Mon, 18 Apr 2011 11:21:06 -0500 Subject: QtDBus: Fix registering objects using path '/' in peer-to-peer connections Merge-request: 2343 Reviewed-by: Marius Storm-Olsen Reviewed-by: Thiago Macieira --- src/dbus/qdbusconnection.cpp | 2 +- src/dbus/qdbusintegrator.cpp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/dbus/qdbusconnection.cpp b/src/dbus/qdbusconnection.cpp index a7ee5b9..f78d7da 100644 --- a/src/dbus/qdbusconnection.cpp +++ b/src/dbus/qdbusconnection.cpp @@ -814,7 +814,7 @@ void QDBusConnection::unregisterObject(const QString &path, UnregisterMode mode) // find the object while (node) { - if (pathComponents.count() == i) { + if (pathComponents.count() == i || !path.compare(QLatin1String("/"))) { // found it node->obj = 0; node->flags = 0; diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp index e09b155..10f749b 100644 --- a/src/dbus/qdbusintegrator.cpp +++ b/src/dbus/qdbusintegrator.cpp @@ -430,6 +430,11 @@ static bool findObject(const QDBusConnectionPrivate::ObjectTreeNode *root, const QString &fullpath, int &usedLength, QDBusConnectionPrivate::ObjectTreeNode &result) { + if (!fullpath.compare(QLatin1String("/")) && root->obj) { + usedLength = 1; + result = *root; + return root; + } int start = 0; int length = fullpath.length(); if (fullpath.at(0) == QLatin1Char('/')) -- cgit v0.12 From fdf12afc9aaa1432f24817229863baaa68ec13ab Mon Sep 17 00:00:00 2001 From: "Daniele E. Domenichelli" Date: Mon, 18 Apr 2011 11:21:07 -0500 Subject: QtDBus: Fix empty service name in peer-to-peer connections Merge-request: 2343 Reviewed-by: Marius Storm-Olsen Reviewed-by: Thiago Macieira --- src/dbus/qdbusabstractinterface.cpp | 2 +- src/dbus/qdbusintegrator.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dbus/qdbusabstractinterface.cpp b/src/dbus/qdbusabstractinterface.cpp index e48e1c0..d15eb7d 100644 --- a/src/dbus/qdbusabstractinterface.cpp +++ b/src/dbus/qdbusabstractinterface.cpp @@ -107,7 +107,7 @@ bool QDBusAbstractInterfacePrivate::canMakeCalls() const { // recheck only if we have a wildcard (i.e. empty) service or path // if any are empty, set the error message according to QDBusUtil - if (service.isEmpty()) + if (service.isEmpty() && connectionPrivate()->mode != QDBusConnectionPrivate::PeerMode) return QDBusUtil::checkBusName(service, QDBusUtil::EmptyNotAllowed, &lastError); if (path.isEmpty()) return QDBusUtil::checkObjectPath(path, QDBusUtil::EmptyNotAllowed, &lastError); diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp index 10f749b..269e885 100644 --- a/src/dbus/qdbusintegrator.cpp +++ b/src/dbus/qdbusintegrator.cpp @@ -2390,7 +2390,7 @@ void QDBusConnectionPrivate::unregisterServiceNoLock(const QString &serviceName) bool QDBusConnectionPrivate::isServiceRegisteredByThread(const QString &serviceName) const { - if (serviceName == baseService) + if (!serviceName.isEmpty() && serviceName == baseService) return true; QStringList copy = serviceNames; return copy.contains(serviceName); -- cgit v0.12 From 7d4e64736774fb0d91f98978af91577461265815 Mon Sep 17 00:00:00 2001 From: "Daniele E. Domenichelli" Date: Mon, 18 Apr 2011 11:21:08 -0500 Subject: QtDBus: Fix bus in peer-to-peer connections should not be used Merge-request: 2343 Reviewed-by: Marius Storm-Olsen Reviewed-by: Thiago Macieira --- src/dbus/qdbusintegrator.cpp | 58 +++++++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp index 269e885..b8698de 100644 --- a/src/dbus/qdbusintegrator.cpp +++ b/src/dbus/qdbusintegrator.cpp @@ -2098,21 +2098,23 @@ void QDBusConnectionPrivate::connectSignal(const QString &key, const SignalHook matchRefCounts.insert(hook.matchRule, 1); if (connection) { - qDBusDebug("Adding rule: %s", hook.matchRule.constData()); - q_dbus_bus_add_match(connection, hook.matchRule, NULL); - - // Successfully connected the signal - // Do we need to watch for this name? - if (shouldWatchService(hook.service)) { - WatchedServicesHash::mapped_type &data = watchedServices[hook.service]; - if (++data.refcount == 1) { - // we need to watch for this service changing - connectSignal(dbusServiceString(), QString(), dbusInterfaceString(), - QLatin1String("NameOwnerChanged"), QStringList() << hook.service, QString(), - this, SLOT(serviceOwnerChangedNoLock(QString,QString,QString))); - data.owner = getNameOwnerNoCache(hook.service); - qDBusDebug() << this << "Watching service" << hook.service << "for owner changes (current owner:" - << data.owner << ")"; + if (mode != QDBusConnectionPrivate::PeerMode) { + qDBusDebug("Adding rule: %s", hook.matchRule.constData()); + q_dbus_bus_add_match(connection, hook.matchRule, NULL); + + // Successfully connected the signal + // Do we need to watch for this name? + if (shouldWatchService(hook.service)) { + WatchedServicesHash::mapped_type &data = watchedServices[hook.service]; + if (++data.refcount == 1) { + // we need to watch for this service changing + connectSignal(dbusServiceString(), QString(), dbusInterfaceString(), + QLatin1String("NameOwnerChanged"), QStringList() << hook.service, QString(), + this, SLOT(serviceOwnerChangedNoLock(QString,QString,QString))); + data.owner = getNameOwnerNoCache(hook.service); + qDBusDebug() << this << "Watching service" << hook.service << "for owner changes (current owner:" + << data.owner << ")"; + } } } } @@ -2176,18 +2178,20 @@ QDBusConnectionPrivate::disconnectSignal(SignalHookHash::Iterator &it) // we don't care about errors here if (connection && erase) { - qDBusDebug("Removing rule: %s", hook.matchRule.constData()); - q_dbus_bus_remove_match(connection, hook.matchRule, NULL); - - // Successfully disconnected the signal - // Were we watching for this name? - WatchedServicesHash::Iterator sit = watchedServices.find(hook.service); - if (sit != watchedServices.end()) { - if (--sit.value().refcount == 0) { - watchedServices.erase(sit); - disconnectSignal(dbusServiceString(), QString(), dbusInterfaceString(), - QLatin1String("NameOwnerChanged"), QStringList() << hook.service, QString(), - this, SLOT(_q_serviceOwnerChanged(QString,QString,QString))); + if (mode != QDBusConnectionPrivate::PeerMode) { + qDBusDebug("Removing rule: %s", hook.matchRule.constData()); + q_dbus_bus_remove_match(connection, hook.matchRule, NULL); + + // Successfully disconnected the signal + // Were we watching for this name? + WatchedServicesHash::Iterator sit = watchedServices.find(hook.service); + if (sit != watchedServices.end()) { + if (--sit.value().refcount == 0) { + watchedServices.erase(sit); + disconnectSignal(dbusServiceString(), QString(), dbusInterfaceString(), + QLatin1String("NameOwnerChanged"), QStringList() << hook.service, QString(), + this, SLOT(_q_serviceOwnerChanged(QString,QString,QString))); + } } } -- cgit v0.12 From 9ac6b01ec67ead91143f7c722dbfab38f94dc8c3 Mon Sep 17 00:00:00 2001 From: "Daniele E. Domenichelli" Date: Mon, 18 Apr 2011 11:21:09 -0500 Subject: QtDBus: Fix QDBusConnection::disconnectFromBus() for peer-to-peer connections Merge-request: 2343 Reviewed-by: Marius Storm-Olsen Reviewed-by: Thiago Macieira --- src/dbus/qdbusconnection.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/dbus/qdbusconnection.cpp b/src/dbus/qdbusconnection.cpp index f78d7da..0d28c30 100644 --- a/src/dbus/qdbusconnection.cpp +++ b/src/dbus/qdbusconnection.cpp @@ -424,6 +424,9 @@ void QDBusConnection::disconnectFromBus(const QString &name) { if (_q_manager()) { QMutexLocker locker(&_q_manager()->mutex); + QDBusConnectionPrivate *d = _q_manager()->connection(name); + if(d && d->mode != QDBusConnectionPrivate::ClientMode) + return; _q_manager()->removeConnection(name); } } -- cgit v0.12 From 0792182c396c531d8b9d660df97849ef094c1023 Mon Sep 17 00:00:00 2001 From: "Daniele E. Domenichelli" Date: Mon, 18 Apr 2011 11:21:10 -0500 Subject: QtDBus: Add method QDBusConnection::connectToPeer() Merge-request: 2343 Reviewed-by: Marius Storm-Olsen Reviewed-by: Thiago Macieira --- src/dbus/qdbusconnection.cpp | 34 ++++++++++++++++++++++++++++++++++ src/dbus/qdbusconnection.h | 1 + 2 files changed, 35 insertions(+) diff --git a/src/dbus/qdbusconnection.cpp b/src/dbus/qdbusconnection.cpp index 0d28c30..6df95ec 100644 --- a/src/dbus/qdbusconnection.cpp +++ b/src/dbus/qdbusconnection.cpp @@ -411,6 +411,40 @@ QDBusConnection QDBusConnection::connectToBus(const QString &address, return retval; } +/*! + \since 4.8 + + Opens a peer-to-peer connection on address \a address and associate with it the + connection name \a name. Returns a QDBusConnection object associated with that connection. +*/ +QDBusConnection QDBusConnection::connectToPeer(const QString &address, + const QString &name) +{ +// Q_ASSERT_X(QCoreApplication::instance(), "QDBusConnection::addConnection", +// "Cannot create connection without a Q[Core]Application instance"); + if (!qdbus_loadLibDBus()){ + QDBusConnectionPrivate *d = 0; + return QDBusConnection(d); + } + + QMutexLocker locker(&_q_manager()->mutex); + + QDBusConnectionPrivate *d = _q_manager()->connection(name); + if (d || name.isEmpty()) + return QDBusConnection(d); + + d = new QDBusConnectionPrivate; + // setPeer does the error handling for us + QDBusErrorInternal error; + DBusConnection *c = q_dbus_connection_open_private(address.toUtf8().constData(), error); + + d->setPeer(c, error); + _q_manager()->setConnection(name, d); + + QDBusConnection retval(d); + + return retval; +} /*! Closes the bus connection of name \a name. diff --git a/src/dbus/qdbusconnection.h b/src/dbus/qdbusconnection.h index 6ab0ea2..8aa0726 100644 --- a/src/dbus/qdbusconnection.h +++ b/src/dbus/qdbusconnection.h @@ -172,6 +172,7 @@ public: static QDBusConnection connectToBus(BusType type, const QString &name); static QDBusConnection connectToBus(const QString &address, const QString &name); + static QDBusConnection connectToPeer(const QString &address, const QString &name); static void disconnectFromBus(const QString &name); static QDBusConnection sessionBus(); -- cgit v0.12 From e6c46787ff5b8ac2bd700c35b6e04d7c835b1c23 Mon Sep 17 00:00:00 2001 From: "Daniele E. Domenichelli" Date: Mon, 18 Apr 2011 11:21:10 -0500 Subject: QtDBus: Add method QDBusConnection::disconnectFromPeer() Merge-request: 2343 Reviewed-by: Marius Storm-Olsen Reviewed-by: Thiago Macieira --- src/dbus/qdbusconnection.cpp | 21 +++++++++++++++++++++ src/dbus/qdbusconnection.h | 1 + 2 files changed, 22 insertions(+) diff --git a/src/dbus/qdbusconnection.cpp b/src/dbus/qdbusconnection.cpp index 6df95ec..dea7cf9 100644 --- a/src/dbus/qdbusconnection.cpp +++ b/src/dbus/qdbusconnection.cpp @@ -466,6 +466,27 @@ void QDBusConnection::disconnectFromBus(const QString &name) } /*! + \since 4.8 + + Closes the peer connection of name \a name. + + Note that if there are still QDBusConnection objects associated + with the same connection, the connection will not be closed until + all references are dropped. However, no further references can be + created using the QDBusConnection constructor. +*/ +void QDBusConnection::disconnectFromPeer(const QString &name) +{ + if (_q_manager()) { + QMutexLocker locker(&_q_manager()->mutex); + QDBusConnectionPrivate *d = _q_manager()->connection(name); + if(d && d->mode != QDBusConnectionPrivate::PeerMode) + return; + _q_manager()->removeConnection(name); + } +} + +/*! Sends the \a message over this connection, without waiting for a reply. This is suitable for errors, signals, and return values as well as calls whose return values are not necessary. diff --git a/src/dbus/qdbusconnection.h b/src/dbus/qdbusconnection.h index 8aa0726..15e08a7 100644 --- a/src/dbus/qdbusconnection.h +++ b/src/dbus/qdbusconnection.h @@ -174,6 +174,7 @@ public: static QDBusConnection connectToBus(const QString &address, const QString &name); static QDBusConnection connectToPeer(const QString &address, const QString &name); static void disconnectFromBus(const QString &name); + static void disconnectFromPeer(const QString &name); static QDBusConnection sessionBus(); static QDBusConnection systemBus(); -- cgit v0.12 From cb3bed20f66d36057db971e4feb75c9823cb19a8 Mon Sep 17 00:00:00 2001 From: "Daniele E. Domenichelli" Date: Mon, 18 Apr 2011 11:21:11 -0500 Subject: QtDBus: Add unit tests for peer-to-peer connection Merge-request: 2343 Reviewed-by: Marius Storm-Olsen Reviewed-by: Thiago Macieira --- tests/auto/qdbusconnection/tst_qdbusconnection.cpp | 382 +++++++++++++++++++++ 1 file changed, 382 insertions(+) diff --git a/tests/auto/qdbusconnection/tst_qdbusconnection.cpp b/tests/auto/qdbusconnection/tst_qdbusconnection.cpp index 8e3a44b..dcd3d98 100644 --- a/tests/auto/qdbusconnection/tst_qdbusconnection.cpp +++ b/tests/auto/qdbusconnection/tst_qdbusconnection.cpp @@ -86,6 +86,7 @@ public slots: private slots: void noConnection(); void connectToBus(); + void connectToPeer(); void connect(); void send(); void sendWithGui(); @@ -94,9 +95,13 @@ private slots: void registerObject_data(); void registerObject(); + void registerObjectPeer_data(); + void registerObjectPeer(); void registerObject2(); + void registerObjectPeer2(); void registerQObjectChildren(); + void registerQObjectChildrenPeer(); void callSelf(); void callSelfByAnotherName_data(); @@ -111,6 +116,7 @@ private slots: public: QString serviceName() const { return "com.trolltech.Qt.Autotests.QDBusConnection"; } bool callMethod(const QDBusConnection &conn, const QString &path); + bool callMethodPeer(const QDBusConnection &conn, const QString &path); }; class QDBusSpy: public QObject @@ -259,6 +265,14 @@ void tst_QDBusConnection::connectToBus() QVERIFY(!con.lastError().isValid()); } + QDBusConnection::disconnectFromPeer("bubu"); + + { + QDBusConnection con("bubu"); + QVERIFY(con.isConnected()); + QVERIFY(!con.lastError().isValid()); + } + QDBusConnection::disconnectFromBus("bubu"); { @@ -277,6 +291,65 @@ void tst_QDBusConnection::connectToBus() } } +void tst_QDBusConnection::connectToPeer() +{ + { + QDBusConnection con = QDBusConnection::connectToPeer( + "", "newconn"); + QVERIFY(!con.isConnected()); + QVERIFY(con.lastError().isValid()); + } + + QDBusServer server("unix:tmpdir=/tmp", 0); + + { + QDBusConnection con = QDBusConnection::connectToPeer( + "unix:abstract=/tmp/dbus-XXXXXXXXXX,guid=00000000000000000000000000000000", "newconn2"); + QVERIFY(!con.isConnected()); + QVERIFY(con.lastError().isValid()); + } + + { + QDBusConnection con = QDBusConnection::connectToPeer( + server.address(), "bubu"); + + QVERIFY(con.isConnected()); + QVERIFY(!con.lastError().isValid()); + + QDBusConnection con2("foo"); + QVERIFY(!con2.isConnected()); + QVERIFY(!con2.lastError().isValid()); + + con2 = con; + QVERIFY(con.isConnected()); + QVERIFY(con2.isConnected()); + QVERIFY(!con.lastError().isValid()); + QVERIFY(!con2.lastError().isValid()); + } + + { + QDBusConnection con("bubu"); + QVERIFY(con.isConnected()); + QVERIFY(!con.lastError().isValid()); + } + + QDBusConnection::disconnectFromBus("bubu"); + + { + QDBusConnection con("bubu"); + QVERIFY(con.isConnected()); + QVERIFY(!con.lastError().isValid()); + } + + QDBusConnection::disconnectFromPeer("bubu"); + + { + QDBusConnection con("bubu"); + QVERIFY(!con.isConnected()); + QVERIFY(!con.lastError().isValid()); + } +} + void tst_QDBusConnection::registerObject_data() { QTest::addColumn("path"); @@ -308,6 +381,106 @@ void tst_QDBusConnection::registerObject() QVERIFY(!callMethod(con, path)); } +class MyServer : public QDBusServer +{ + Q_OBJECT +public: + MyServer(QString path, QString addr, QObject* parent) : QDBusServer(addr, parent), + m_path(path), + m_conn("none") + { + connect(this, SIGNAL(newConnection(const QDBusConnection&)), SLOT(handleConnection(const QDBusConnection&))); + } + + bool registerObject() + { + if( !m_conn.registerObject(m_path, &m_obj, QDBusConnection::ExportAllSlots) ) + return false; + if(! (m_conn.objectRegisteredAt(m_path) == &m_obj)) + return false; + return true; + } + + void unregisterObject() + { + m_conn.unregisterObject(m_path); + } + +public slots: + void handleConnection(const QDBusConnection& c) + { + m_conn = c; + QVERIFY(isConnected()); + QVERIFY(m_conn.isConnected()); + QVERIFY(registerObject()); + } + +private: + MyObject m_obj; + QString m_path; + QDBusConnection m_conn; +}; + + +void tst_QDBusConnection::registerObjectPeer_data() +{ + QTest::addColumn("path"); + + QTest::newRow("/") << "/"; + QTest::newRow("/p1") << "/p1"; + QTest::newRow("/p2") << "/p2"; + QTest::newRow("/p1/q") << "/p1/q"; + QTest::newRow("/p1/q/r") << "/p1/q/r"; +} + +void tst_QDBusConnection::registerObjectPeer() +{ + QFETCH(QString, path); + + MyServer server(path, "unix:tmpdir=/tmp", 0); + + { + QDBusConnection con = QDBusConnection::connectToPeer(server.address(), "foo"); + + QCoreApplication::processEvents(); + QVERIFY(con.isConnected()); + + MyObject obj; + QVERIFY(callMethodPeer(con, path)); + QCOMPARE(obj.path, path); + } + + { + QDBusConnection con("foo"); + QVERIFY(con.isConnected()); + QVERIFY(callMethodPeer(con, path)); + } + + server.unregisterObject(); + + { + QDBusConnection con("foo"); + QVERIFY(con.isConnected()); + QVERIFY(!callMethodPeer(con, path)); + } + + server.registerObject(); + + { + QDBusConnection con("foo"); + QVERIFY(con.isConnected()); + QVERIFY(callMethodPeer(con, path)); + } + + QDBusConnection::disconnectFromPeer("foo"); + + { + QDBusConnection con("foo"); + QVERIFY(!con.isConnected()); + QVERIFY(!callMethodPeer(con, path)); + } +} + void tst_QDBusConnection::registerObject2() { QDBusConnection con = QDBusConnection::sessionBus(); @@ -401,6 +574,134 @@ void tst_QDBusConnection::registerObject2() } } +class MyServer2 : public QDBusServer +{ + Q_OBJECT +public: + MyServer2(QString addr, QObject* parent) : QDBusServer(addr, parent), + m_conn("none") + { + connect(this, SIGNAL(newConnection(const QDBusConnection&)), SLOT(handleConnection(const QDBusConnection&))); + } + + QDBusConnection connection() + { + return m_conn; + } + +public slots: + void handleConnection(const QDBusConnection& c) + { + m_conn = c; + QVERIFY(isConnected()); + QVERIFY(m_conn.isConnected()); + } + +private: + MyObject m_obj; + QDBusConnection m_conn; +}; + +void tst_QDBusConnection::registerObjectPeer2() +{ + MyServer2 server("unix:tmpdir=/tmp", 0); + QDBusConnection con = QDBusConnection::connectToPeer(server.address(), "foo"); + QCoreApplication::processEvents(); + QVERIFY(con.isConnected()); + + QDBusConnection srv_con = server.connection(); + + // make sure nothing is using our paths: + QVERIFY(!callMethodPeer(srv_con, "/")); + QVERIFY(!callMethodPeer(srv_con, "/p1")); + QVERIFY(!callMethodPeer(srv_con, "/p2")); + QVERIFY(!callMethodPeer(srv_con, "/p1/q")); + QVERIFY(!callMethodPeer(srv_con, "/p1/q/r")); + + { + // register one object at root: + MyObject obj; + QVERIFY(con.registerObject("/", &obj, QDBusConnection::ExportAllSlots)); + QVERIFY(callMethodPeer(srv_con, "/")); + qDebug() << obj.path; + QCOMPARE(obj.path, QString("/")); + } + // make sure it's gone + QVERIFY(!callMethodPeer(srv_con, "/")); + + { + // register one at an element: + MyObject obj; + QVERIFY(con.registerObject("/p1", &obj, QDBusConnection::ExportAllSlots)); + QVERIFY(!callMethodPeer(srv_con, "/")); + QVERIFY(callMethodPeer(srv_con, "/p1")); + qDebug() << obj.path; + QCOMPARE(obj.path, QString("/p1")); + + // re-register it somewhere else + QVERIFY(con.registerObject("/p2", &obj, QDBusConnection::ExportAllSlots)); + QVERIFY(callMethodPeer(srv_con, "/p1")); + QCOMPARE(obj.path, QString("/p1")); + QVERIFY(callMethodPeer(srv_con, "/p2")); + QCOMPARE(obj.path, QString("/p2")); + } + // make sure it's gone + QVERIFY(!callMethodPeer(srv_con, "/p1")); + QVERIFY(!callMethodPeer(srv_con, "/p2")); + + { + // register at a deep path + MyObject obj; + QVERIFY(con.registerObject("/p1/q/r", &obj, QDBusConnection::ExportAllSlots)); + QVERIFY(!callMethodPeer(srv_con, "/")); + QVERIFY(!callMethodPeer(srv_con, "/p1")); + QVERIFY(!callMethodPeer(srv_con, "/p1/q")); + QVERIFY(callMethodPeer(srv_con, "/p1/q/r")); + QCOMPARE(obj.path, QString("/p1/q/r")); + } + // make sure it's gone + QVERIFY(!callMethodPeer(srv_con, "/p1/q/r")); + + { + MyObject obj; + QVERIFY(con.registerObject("/p1/q2", &obj, QDBusConnection::ExportAllSlots)); + QVERIFY(callMethodPeer(srv_con, "/p1/q2")); + QCOMPARE(obj.path, QString("/p1/q2")); + + // try unregistering + con.unregisterObject("/p1/q2"); + QVERIFY(!callMethodPeer(srv_con, "/p1/q2")); + + // register it again + QVERIFY(con.registerObject("/p1/q2", &obj, QDBusConnection::ExportAllSlots)); + QVERIFY(callMethodPeer(srv_con, "/p1/q2")); + QCOMPARE(obj.path, QString("/p1/q2")); + + // now try removing things around it: + con.unregisterObject("/p2"); + QVERIFY(callMethodPeer(srv_con, "/p1/q2")); // unrelated object shouldn't affect + + con.unregisterObject("/p1"); + QVERIFY(callMethodPeer(srv_con, "/p1/q2")); // unregistering just the parent shouldn't affect it + + con.unregisterObject("/p1/q2/r"); + QVERIFY(callMethodPeer(srv_con, "/p1/q2")); // unregistering non-existing child shouldn't affect it either + + con.unregisterObject("/p1/q"); + QVERIFY(callMethodPeer(srv_con, "/p1/q2")); // unregistering sibling (before) shouldn't affect + + con.unregisterObject("/p1/r"); + QVERIFY(callMethodPeer(srv_con, "/p1/q2")); // unregistering sibling (after) shouldn't affect + + // now remove it: + con.unregisterObject("/p1", QDBusConnection::UnregisterTree); + QVERIFY(!callMethodPeer(srv_con, "/p1/q2")); // we removed the full tree + } + + QDBusConnection::disconnectFromPeer("foo"); +} + + void tst_QDBusConnection::registerQObjectChildren() { // make sure no one is there @@ -456,6 +757,68 @@ void tst_QDBusConnection::registerQObjectChildren() QVERIFY(!callMethod(con, "/p1/c/cc")); } +void tst_QDBusConnection::registerQObjectChildrenPeer() +{ + MyServer2 server("unix:tmpdir=/tmp", 0); + QDBusConnection con = QDBusConnection::connectToPeer(server.address(), "foo"); + QCoreApplication::processEvents(); + QVERIFY(con.isConnected()); + + QDBusConnection srv_con = server.connection(); + + QVERIFY(!callMethodPeer(srv_con, "/p1")); + + { + MyObject obj, *a, *b, *c, *cc; + + a = new MyObject(&obj); + a->setObjectName("a"); + + b = new MyObject(&obj); + b->setObjectName("b"); + + c = new MyObject(&obj); + c->setObjectName("c"); + + cc = new MyObject(c); + cc->setObjectName("cc"); + + con.registerObject("/p1", &obj, QDBusConnection::ExportAllSlots | + QDBusConnection::ExportChildObjects); + + // make calls + QVERIFY(callMethodPeer(srv_con, "/p1")); + QCOMPARE(obj.callCount, 1); + QVERIFY(callMethodPeer(srv_con, "/p1/a")); + QCOMPARE(a->callCount, 1); + QVERIFY(callMethodPeer(srv_con, "/p1/b")); + QCOMPARE(b->callCount, 1); + QVERIFY(callMethodPeer(srv_con, "/p1/c")); + QCOMPARE(c->callCount, 1); + QVERIFY(callMethodPeer(srv_con, "/p1/c/cc")); + QCOMPARE(cc->callCount, 1); + + QVERIFY(!callMethodPeer(srv_con, "/p1/d")); + QVERIFY(!callMethodPeer(srv_con, "/p1/c/abc")); + + // pull an object, see if it goes away: + delete b; + QVERIFY(!callMethodPeer(srv_con, "/p1/b")); + + delete c; + QVERIFY(!callMethodPeer(srv_con, "/p1/c")); + QVERIFY(!callMethodPeer(srv_con, "/p1/c/cc")); + } + + QVERIFY(!callMethodPeer(srv_con, "/p1")); + QVERIFY(!callMethodPeer(srv_con, "/p1/a")); + QVERIFY(!callMethodPeer(srv_con, "/p1/b")); + QVERIFY(!callMethodPeer(srv_con, "/p1/c")); + QVERIFY(!callMethodPeer(srv_con, "/p1/c/cc")); + + QDBusConnection::disconnectFromPeer("foo"); +} + bool tst_QDBusConnection::callMethod(const QDBusConnection &conn, const QString &path) { QDBusMessage msg = QDBusMessage::createMethodCall(conn.baseService(), path, "", "method"); @@ -475,6 +838,25 @@ bool tst_QDBusConnection::callMethod(const QDBusConnection &conn, const QString return true; } +bool tst_QDBusConnection::callMethodPeer(const QDBusConnection &conn, const QString &path) +{ + QDBusMessage msg = QDBusMessage::createMethodCall("", path, "", "method"); + QDBusMessage reply = conn.call(msg, QDBus::BlockWithGui); + + if (reply.type() != QDBusMessage::ReplyMessage) + return false; + if (MyObject::path == path) { + QTest::compare_helper(true, "COMPARE()", __FILE__, __LINE__); + } else { + QTest::compare_helper(false, "Compared values are not the same", + QTest::toString(MyObject::path), QTest::toString(path), + "MyObject::path", "path", __FILE__, __LINE__); + return false; + } + + return true; +} + class TestObject : public QObject { Q_OBJECT -- cgit v0.12 From 5be6cf0a6e306ed3a51ed5ba89317b1317544eea Mon Sep 17 00:00:00 2001 From: "Daniele E. Domenichelli" Date: Mon, 18 Apr 2011 11:21:12 -0500 Subject: QtDBus: Add default constructor to QDBusServer Merge-request: 2343 Reviewed-by: Marius Storm-Olsen Reviewed-by: Thiago Macieira --- src/dbus/qdbusserver.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dbus/qdbusserver.h b/src/dbus/qdbusserver.h index f101011..eedbe0f 100644 --- a/src/dbus/qdbusserver.h +++ b/src/dbus/qdbusserver.h @@ -61,7 +61,7 @@ class Q_DBUS_EXPORT QDBusServer: public QObject { Q_OBJECT public: - QDBusServer(const QString &address, QObject *parent = 0); + QDBusServer(const QString &address = "unix:tmpdir=/tmp", QObject *parent = 0); bool isConnected() const; QDBusError lastError() const; -- cgit v0.12 From a25ec261a52685792527c77e4de0dee28e300bbb Mon Sep 17 00:00:00 2001 From: "Daniele E. Domenichelli" Date: Mon, 18 Apr 2011 11:21:13 -0500 Subject: QtDBus: Fix minor coding style issues Merge-request: 2343 Reviewed-by: Marius Storm-Olsen Reviewed-by: Thiago Macieira --- src/dbus/qdbusconnection.cpp | 8 ++++---- src/dbus/qdbusconnection_p.h | 2 +- tests/auto/qdbusconnection/tst_qdbusconnection.cpp | 2 +- tests/auto/qdbusinterface/tst_qdbusinterface.cpp | 16 ++++++++-------- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/dbus/qdbusconnection.cpp b/src/dbus/qdbusconnection.cpp index dea7cf9..2384cf3 100644 --- a/src/dbus/qdbusconnection.cpp +++ b/src/dbus/qdbusconnection.cpp @@ -379,7 +379,7 @@ QDBusConnection QDBusConnection::connectToBus(const QString &address, { // Q_ASSERT_X(QCoreApplication::instance(), "QDBusConnection::addConnection", // "Cannot create connection without a Q[Core]Application instance"); - if (!qdbus_loadLibDBus()){ + if (!qdbus_loadLibDBus()) { QDBusConnectionPrivate *d = 0; return QDBusConnection(d); } @@ -422,7 +422,7 @@ QDBusConnection QDBusConnection::connectToPeer(const QString &address, { // Q_ASSERT_X(QCoreApplication::instance(), "QDBusConnection::addConnection", // "Cannot create connection without a Q[Core]Application instance"); - if (!qdbus_loadLibDBus()){ + if (!qdbus_loadLibDBus()) { QDBusConnectionPrivate *d = 0; return QDBusConnection(d); } @@ -459,7 +459,7 @@ void QDBusConnection::disconnectFromBus(const QString &name) if (_q_manager()) { QMutexLocker locker(&_q_manager()->mutex); QDBusConnectionPrivate *d = _q_manager()->connection(name); - if(d && d->mode != QDBusConnectionPrivate::ClientMode) + if (d && d->mode != QDBusConnectionPrivate::ClientMode) return; _q_manager()->removeConnection(name); } @@ -480,7 +480,7 @@ void QDBusConnection::disconnectFromPeer(const QString &name) if (_q_manager()) { QMutexLocker locker(&_q_manager()->mutex); QDBusConnectionPrivate *d = _q_manager()->connection(name); - if(d && d->mode != QDBusConnectionPrivate::PeerMode) + if (d && d->mode != QDBusConnectionPrivate::PeerMode) return; _q_manager()->removeConnection(name); } diff --git a/src/dbus/qdbusconnection_p.h b/src/dbus/qdbusconnection_p.h index 36f7c53..355a6e6 100644 --- a/src/dbus/qdbusconnection_p.h +++ b/src/dbus/qdbusconnection_p.h @@ -216,7 +216,7 @@ public: inline void serverConnection(const QDBusConnection &connection) { emit newServerConnection(connection); } - + private: void checkThread(); bool handleError(const QDBusErrorInternal &error); diff --git a/tests/auto/qdbusconnection/tst_qdbusconnection.cpp b/tests/auto/qdbusconnection/tst_qdbusconnection.cpp index dcd3d98..d4a9dab 100644 --- a/tests/auto/qdbusconnection/tst_qdbusconnection.cpp +++ b/tests/auto/qdbusconnection/tst_qdbusconnection.cpp @@ -579,7 +579,7 @@ class MyServer2 : public QDBusServer Q_OBJECT public: MyServer2(QString addr, QObject* parent) : QDBusServer(addr, parent), - m_conn("none") + m_conn("none") { connect(this, SIGNAL(newConnection(const QDBusConnection&)), SLOT(handleConnection(const QDBusConnection&))); } diff --git a/tests/auto/qdbusinterface/tst_qdbusinterface.cpp b/tests/auto/qdbusinterface/tst_qdbusinterface.cpp index 39f0677..ce11459 100644 --- a/tests/auto/qdbusinterface/tst_qdbusinterface.cpp +++ b/tests/auto/qdbusinterface/tst_qdbusinterface.cpp @@ -369,7 +369,7 @@ void tst_QDBusInterface::callMethod() TEST_INTERFACE_NAME); MyObject::callCount = 0; - + // call a SLOT method QDBusMessage reply = iface.call("ping", qVariantFromValue(QDBusVariant("foo"))); QCOMPARE(MyObject::callCount, 1); @@ -388,7 +388,7 @@ void tst_QDBusInterface::callMethod() dv = qdbus_cast(v); QCOMPARE(dv.variant().type(), QVariant::String); QCOMPARE(dv.variant().toString(), QString("foo")); - + // call an INVOKABLE method reply = iface.call("ping_invokable", qVariantFromValue(QDBusVariant("bar"))); QCOMPARE(MyObject::callCount, 2); @@ -416,7 +416,7 @@ void tst_QDBusInterface::invokeMethod() TEST_INTERFACE_NAME); MyObject::callCount = 0; - + // make the SLOT call without a return type QDBusVariant arg("foo"); QVERIFY(QMetaObject::invokeMethod(&iface, "ping", Q_ARG(QDBusVariant, arg))); @@ -428,7 +428,7 @@ void tst_QDBusInterface::invokeMethod() QDBusVariant dv = qdbus_cast(v); QCOMPARE(dv.variant().type(), QVariant::String); QCOMPARE(dv.variant().toString(), QString("foo")); - + // make the INVOKABLE call without a return type QDBusVariant arg2("bar"); QVERIFY(QMetaObject::invokeMethod(&iface, "ping_invokable", Q_ARG(QDBusVariant, arg2))); @@ -465,7 +465,7 @@ void tst_QDBusInterface::invokeMethodWithReturn() // verify that we got the reply as expected QCOMPARE(retArg.variant(), arg.variant()); - + // make the INVOKABLE call without a return type QDBusVariant arg2("bar"); QVERIFY(QMetaObject::invokeMethod(&iface, "ping_invokable", Q_RETURN_ARG(QDBusVariant, retArg), Q_ARG(QDBusVariant, arg2))); @@ -490,7 +490,7 @@ void tst_QDBusInterface::invokeMethodWithMultiReturn() MyObject::callCount = 0; QDBusVariant retArg, retArg2; - + // make the SLOT call without a return type QDBusVariant arg("foo"), arg2("bar"); QVERIFY(QMetaObject::invokeMethod(&iface, "ping", @@ -515,7 +515,7 @@ void tst_QDBusInterface::invokeMethodWithMultiReturn() // verify that we got the replies as expected QCOMPARE(retArg.variant(), arg.variant()); QCOMPARE(retArg2.variant(), arg2.variant()); - + // make the INVOKABLE call without a return type QDBusVariant arg3("hello"), arg4("world"); QVERIFY(QMetaObject::invokeMethod(&iface, "ping_invokable", @@ -550,7 +550,7 @@ void tst_QDBusInterface::invokeMethodWithComplexReturn() MyObject::callCount = 0; QList retArg; - + // make the SLOT call without a return type QList arg = QList() << 42 << -47; QVERIFY(QMetaObject::invokeMethod(&iface, "ping", Q_RETURN_ARG(QList, retArg), Q_ARG(QList, arg))); -- cgit v0.12 From b9eb6a61392dd025745708e6a5d60a4f019ef32e Mon Sep 17 00:00:00 2001 From: "Daniele E. Domenichelli" Date: Mon, 18 Apr 2011 11:21:14 -0500 Subject: QtDBus: Skip bus name check for peer-to-peer connection Merge-request: 2343 Reviewed-by: Marius Storm-Olsen Reviewed-by: Thiago Macieira --- src/dbus/qdbusabstractinterface.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/dbus/qdbusabstractinterface.cpp b/src/dbus/qdbusabstractinterface.cpp index d15eb7d..9e82c09 100644 --- a/src/dbus/qdbusabstractinterface.cpp +++ b/src/dbus/qdbusabstractinterface.cpp @@ -58,7 +58,7 @@ QT_BEGIN_NAMESPACE static QDBusError checkIfValid(const QString &service, const QString &path, - const QString &interface, bool isDynamic) + const QString &interface, bool isDynamic, bool isPeer) { // We should be throwing exceptions here... oh well QDBusError error; @@ -69,7 +69,7 @@ static QDBusError checkIfValid(const QString &service, const QString &path, // use assertion here because this should never happen, at all Q_ASSERT_X(!interface.isEmpty(), "QDBusAbstractInterface", "Interface name cannot be empty"); } - if (!QDBusUtil::checkBusName(service, isDynamic ? QDBusUtil::EmptyNotAllowed : QDBusUtil::EmptyAllowed, &error)) + if (!QDBusUtil::checkBusName(service, (isDynamic && !isPeer) ? QDBusUtil::EmptyNotAllowed : QDBusUtil::EmptyAllowed, &error)) return error; if (!QDBusUtil::checkObjectPath(path, isDynamic ? QDBusUtil::EmptyNotAllowed : QDBusUtil::EmptyAllowed, &error)) return error; @@ -86,7 +86,8 @@ QDBusAbstractInterfacePrivate::QDBusAbstractInterfacePrivate(const QString &serv const QDBusConnection& con, bool isDynamic) : connection(con), service(serv), path(p), interface(iface), - lastError(checkIfValid(serv, p, iface, isDynamic)), + lastError(checkIfValid(serv, p, iface, isDynamic, (connectionPrivate() && + connectionPrivate()->mode == QDBusConnectionPrivate::PeerMode))), isValid(!lastError.isValid()) { if (!isValid) -- cgit v0.12 From c48dce786b99acb4bd85863d09df456c03471ef2 Mon Sep 17 00:00:00 2001 From: "Daniele E. Domenichelli" Date: Mon, 18 Apr 2011 11:21:15 -0500 Subject: QtDBus: Register QDBusServer connection name in QDBusConnectionManager Merge-request: 2343 Reviewed-by: Marius Storm-Olsen Reviewed-by: Thiago Macieira --- src/dbus/qdbusconnection.cpp | 27 +++--------- src/dbus/qdbusconnectionmanager_p.h | 88 +++++++++++++++++++++++++++++++++++++ src/dbus/qdbusserver.cpp | 15 ++++++- src/dbus/qdbusserver.h | 1 + 4 files changed, 109 insertions(+), 22 deletions(-) create mode 100644 src/dbus/qdbusconnectionmanager_p.h diff --git a/src/dbus/qdbusconnection.cpp b/src/dbus/qdbusconnection.cpp index 2384cf3..c8cf6ea 100644 --- a/src/dbus/qdbusconnection.cpp +++ b/src/dbus/qdbusconnection.cpp @@ -52,6 +52,7 @@ #include "qdbusconnection_p.h" #include "qdbusinterface_p.h" #include "qdbusutil_p.h" +#include "qdbusconnectionmanager_p.h" #include "qdbusthreaddebug_p.h" @@ -59,27 +60,6 @@ QT_BEGIN_NAMESPACE -class QDBusConnectionManager -{ -public: - QDBusConnectionManager() {} - ~QDBusConnectionManager(); - - QDBusConnectionPrivate *connection(const QString &name) const; - void removeConnection(const QString &name); - void setConnection(const QString &name, QDBusConnectionPrivate *c); - - QDBusConnectionPrivate *sender() const; - void setSender(const QDBusConnectionPrivate *s); - - mutable QMutex mutex; -private: - QHash connectionHash; - - mutable QMutex senderMutex; - QString senderName; // internal; will probably change -}; - Q_GLOBAL_STATIC(QDBusConnectionManager, _q_manager) QDBusConnectionPrivate *QDBusConnectionManager::sender() const @@ -126,6 +106,11 @@ QDBusConnectionManager::~QDBusConnectionManager() connectionHash.clear(); } +QDBusConnectionManager* QDBusConnectionManager::instance() +{ + return _q_manager(); +} + Q_DBUS_EXPORT void qDBusBindToApplication(); void qDBusBindToApplication() { diff --git a/src/dbus/qdbusconnectionmanager_p.h b/src/dbus/qdbusconnectionmanager_p.h new file mode 100644 index 0000000..dd8b4aa --- /dev/null +++ b/src/dbus/qdbusconnectionmanager_p.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDBus 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$ +** +****************************************************************************/ + +// +// W A R N I N G +// ------------- +// +// This file is not part of the public API. This header file may +// change from version to version without notice, or even be +// removed. +// +// We mean it. +// +// + +#ifndef QDBUSCONNECTIONMANAGER_P_H +#define QDBUSCONNECTIONMANAGER_P_H + +#include "qdbusconnection_p.h" + +#ifndef QT_NO_DBUS + +QT_BEGIN_NAMESPACE + +class QDBusConnectionManager +{ +public: + QDBusConnectionManager() {} + ~QDBusConnectionManager(); + static QDBusConnectionManager* instance(); + + QDBusConnectionPrivate *connection(const QString &name) const; + void removeConnection(const QString &name); + void setConnection(const QString &name, QDBusConnectionPrivate *c); + + QDBusConnectionPrivate *sender() const; + void setSender(const QDBusConnectionPrivate *s); + + mutable QMutex mutex; +private: + QHash connectionHash; + + mutable QMutex senderMutex; + QString senderName; // internal; will probably change +}; + +QT_END_NAMESPACE + +#endif // QT_NO_DBUS +#endif diff --git a/src/dbus/qdbusserver.cpp b/src/dbus/qdbusserver.cpp index 3189b4e..abc5cb3 100644 --- a/src/dbus/qdbusserver.cpp +++ b/src/dbus/qdbusserver.cpp @@ -41,6 +41,7 @@ #include "qdbusserver.h" #include "qdbusconnection_p.h" +#include "qdbusconnectionmanager_p.h" #ifndef QT_NO_DBUS @@ -71,7 +72,8 @@ QDBusServer::QDBusServer(const QString &address, QObject *parent) } d = new QDBusConnectionPrivate(this); - d->name = QLatin1String("QDBusServer-") + QString::number(reinterpret_cast(d)); + QMutexLocker locker(&QDBusConnectionManager::instance()->mutex); + QDBusConnectionManager::instance()->setConnection(QLatin1String("QDBusServer-") + QString::number(reinterpret_cast(d)), d); QObject::connect(d, SIGNAL(newServerConnection(QDBusConnection)), this, SIGNAL(newConnection(QDBusConnection))); @@ -81,6 +83,17 @@ QDBusServer::QDBusServer(const QString &address, QObject *parent) } /*! + Destructs a QDBusServer +*/ +QDBusServer::~QDBusServer() +{ + if (QDBusConnectionManager::instance()) { + QMutexLocker locker(&QDBusConnectionManager::instance()->mutex); + QDBusConnectionManager::instance()->removeConnection(d->name); + } +} + +/*! Returns true if this QDBusServer object is connected. If it isn't connected, you need to call the constructor again. diff --git a/src/dbus/qdbusserver.h b/src/dbus/qdbusserver.h index eedbe0f..fcb78bd 100644 --- a/src/dbus/qdbusserver.h +++ b/src/dbus/qdbusserver.h @@ -62,6 +62,7 @@ class Q_DBUS_EXPORT QDBusServer: public QObject Q_OBJECT public: QDBusServer(const QString &address = "unix:tmpdir=/tmp", QObject *parent = 0); + virtual ~QDBusServer(); bool isConnected() const; QDBusError lastError() const; -- cgit v0.12 From 041b89b3905a79a4493399c592797a6321aa29df Mon Sep 17 00:00:00 2001 From: "Daniele E. Domenichelli" Date: Mon, 18 Apr 2011 11:21:16 -0500 Subject: QtDBus: Add unit tests for QDBusAbstractInterface Also fix xml in tests/auto/qdbusabstractinterface/com.trolltech.QtDBus.Pinger.xml Merge-request: 2343 Reviewed-by: Marius Storm-Olsen Reviewed-by: Thiago Macieira --- .../com.trolltech.QtDBus.Pinger.xml | 2 +- tests/auto/qdbusabstractinterface/interface.h | 1 + .../qdbusabstractinterface.pro | 17 +- .../qdbusabstractinterface/qpinger/qpinger.cpp | 131 +++++ .../qdbusabstractinterface/qpinger/qpinger.pro | 5 + tests/auto/qdbusabstractinterface/test/test.pro | 13 + .../tst_qdbusabstractinterface.cpp | 573 +++++++++++++++++++++ 7 files changed, 730 insertions(+), 12 deletions(-) create mode 100644 tests/auto/qdbusabstractinterface/qpinger/qpinger.cpp create mode 100644 tests/auto/qdbusabstractinterface/qpinger/qpinger.pro create mode 100644 tests/auto/qdbusabstractinterface/test/test.pro diff --git a/tests/auto/qdbusabstractinterface/com.trolltech.QtDBus.Pinger.xml b/tests/auto/qdbusabstractinterface/com.trolltech.QtDBus.Pinger.xml index fb2aab8..1667591 100644 --- a/tests/auto/qdbusabstractinterface/com.trolltech.QtDBus.Pinger.xml +++ b/tests/auto/qdbusabstractinterface/com.trolltech.QtDBus.Pinger.xml @@ -24,7 +24,7 @@ - diff --git a/tests/auto/qdbusabstractinterface/interface.h b/tests/auto/qdbusabstractinterface/interface.h index 9a14222..62f81af 100644 --- a/tests/auto/qdbusabstractinterface/interface.h +++ b/tests/auto/qdbusabstractinterface/interface.h @@ -84,6 +84,7 @@ class Interface: public QObject Q_PROPERTY(RegisteredType complexProp READ complexProp WRITE setComplexProp SCRIPTABLE true) friend class tst_QDBusAbstractInterface; + friend class PingerServer; QString m_stringProp; QDBusVariant m_variantProp; RegisteredType m_complexProp; diff --git a/tests/auto/qdbusabstractinterface/qdbusabstractinterface.pro b/tests/auto/qdbusabstractinterface/qdbusabstractinterface.pro index a4853b8..f9077b9 100644 --- a/tests/auto/qdbusabstractinterface/qdbusabstractinterface.pro +++ b/tests/auto/qdbusabstractinterface/qdbusabstractinterface.pro @@ -1,15 +1,10 @@ load(qttest_p4) -QT = core -contains(QT_CONFIG,dbus): { - SOURCES += tst_qdbusabstractinterface.cpp interface.cpp - HEADERS += interface.h - QT += dbus - - # These are generated sources - # To regenerate, see the command-line at the top of the files - SOURCES += pinger.cpp - HEADERS += pinger.h +contains(QT_CONFIG,dbus): { + TEMPLATE = subdirs + CONFIG += ordered + SUBDIRS = qpinger test +} else { + SOURCES += ../qdbusmarshall/dummy.cpp } -else:SOURCES += ../qdbusmarshall/dummy.cpp OTHER_FILES += com.trolltech.QtDBus.Pinger.xml diff --git a/tests/auto/qdbusabstractinterface/qpinger/qpinger.cpp b/tests/auto/qdbusabstractinterface/qpinger/qpinger.cpp new file mode 100644 index 0000000..3b605c8 --- /dev/null +++ b/tests/auto/qdbusabstractinterface/qpinger/qpinger.cpp @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite 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 +#include +#include "../interface.h" + +static const char serviceName[] = "com.trolltech.autotests.qpinger"; +static const char objectPath[] = "/com/trolltech/qpinger"; +//static const char *interfaceName = serviceName; + +class PingerServer : public QDBusServer +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "com.trolltech.autotests.qpinger") +public: + PingerServer(QString addr = "unix:tmpdir=/tmp", QObject* parent = 0) + : QDBusServer(addr, parent), + m_conn("none") + { + connect(this, SIGNAL(newConnection(const QDBusConnection&)), SLOT(handleConnection(const QDBusConnection&))); + reset(); + } + +public slots: + QString address() const + { + return QDBusServer::address(); + } + + bool isConnected() const + { + return m_conn.isConnected(); + } + + void reset() + { + targetObj.m_stringProp = "This is a test"; + targetObj.m_variantProp = QDBusVariant(QVariant(42)); + targetObj.m_complexProp = RegisteredType("This is a test"); + } + + void voidSignal() + { + emit targetObj.voidSignal(); + } + + void stringSignal(const QString& value) + { + emit targetObj.stringSignal(value); + } + + void complexSignal(const QString& value) + { + RegisteredType reg(value); + emit targetObj.complexSignal(reg); + } + +private slots: + void handleConnection(const QDBusConnection& con) + { + m_conn = con; + m_conn.registerObject("/", &targetObj, QDBusConnection::ExportScriptableContents); + } + +private: + Interface targetObj; + QDBusConnection m_conn; +}; + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + + // register the meta types + qDBusRegisterMetaType(); + qRegisterMetaType(); + + QDBusConnection con = QDBusConnection::sessionBus(); + if (!con.isConnected()) + exit(1); + + if (!con.registerService(serviceName)) + exit(2); + + PingerServer server; + con.registerObject(objectPath, &server, QDBusConnection::ExportAllSlots); + + printf("ready.\n"); + + return app.exec(); +} + +#include "qpinger.moc" diff --git a/tests/auto/qdbusabstractinterface/qpinger/qpinger.pro b/tests/auto/qdbusabstractinterface/qpinger/qpinger.pro new file mode 100644 index 0000000..27545bb --- /dev/null +++ b/tests/auto/qdbusabstractinterface/qpinger/qpinger.pro @@ -0,0 +1,5 @@ +SOURCES = qpinger.cpp ../interface.cpp +HEADERS = ../interface.h +TARGET = qpinger +QT += dbus +QT -= gui diff --git a/tests/auto/qdbusabstractinterface/test/test.pro b/tests/auto/qdbusabstractinterface/test/test.pro new file mode 100644 index 0000000..98bcaa7 --- /dev/null +++ b/tests/auto/qdbusabstractinterface/test/test.pro @@ -0,0 +1,13 @@ +load(qttest_p4) +SOURCES += ../tst_qdbusabstractinterface.cpp ../interface.cpp +HEADERS += ../interface.h + +# These are generated sources +# To regenerate, see the command-line at the top of the files +SOURCES += ../pinger.cpp +HEADERS += ../pinger.h + +TARGET = ../tst_qdbusabstractinterface + +QT = core +QT += dbus diff --git a/tests/auto/qdbusabstractinterface/tst_qdbusabstractinterface.cpp b/tests/auto/qdbusabstractinterface/tst_qdbusabstractinterface.cpp index e8ce1f9..6f93d8a 100644 --- a/tests/auto/qdbusabstractinterface/tst_qdbusabstractinterface.cpp +++ b/tests/auto/qdbusabstractinterface/tst_qdbusabstractinterface.cpp @@ -49,6 +49,10 @@ #include "interface.h" #include "pinger.h" +static const char serviceName[] = "com.trolltech.autotests.qpinger"; +static const char objectPath[] = "/com/trolltech/qpinger"; +static const char *interfaceName = serviceName; + typedef QSharedPointer Pinger; class tst_QDBusAbstractInterface: public QObject @@ -66,22 +70,47 @@ class tst_QDBusAbstractInterface: public QObject return Pinger(new com::trolltech::QtDBus::Pinger(service, path, con)); } + Pinger getPingerPeer(const QString &path = "/") + { + QDBusConnection con = QDBusConnection("peer"); + if (!con.isConnected()) + return Pinger(); + return Pinger(new com::trolltech::QtDBus::Pinger("", path, con)); + } + + void resetServer() + { + QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "reset"); + QDBusConnection::sessionBus().send(req); + } + public: tst_QDBusAbstractInterface(); private slots: void initTestCase(); + void cleanupTestCase(); void makeVoidCall(); void makeStringCall(); void makeComplexCall(); void makeMultiOutCall(); + void makeVoidCallPeer(); + void makeStringCallPeer(); + void makeComplexCallPeer(); + void makeMultiOutCallPeer(); + void makeAsyncVoidCall(); void makeAsyncStringCall(); void makeAsyncComplexCall(); void makeAsyncMultiOutCall(); + void makeAsyncVoidCallPeer(); + void makeAsyncStringCallPeer(); + void makeAsyncComplexCallPeer(); + void makeAsyncMultiOutCallPeer(); + void stringPropRead(); void stringPropWrite(); void variantPropRead(); @@ -89,6 +118,13 @@ private slots: void complexPropRead(); void complexPropWrite(); + void stringPropReadPeer(); + void stringPropWritePeer(); + void variantPropReadPeer(); + void variantPropWritePeer(); + void complexPropReadPeer(); + void complexPropWritePeer(); + void stringPropDirectRead(); void stringPropDirectWrite(); void variantPropDirectRead(); @@ -96,6 +132,13 @@ private slots: void complexPropDirectRead(); void complexPropDirectWrite(); + void stringPropDirectReadPeer(); + void stringPropDirectWritePeer(); + void variantPropDirectReadPeer(); + void variantPropDirectWritePeer(); + void complexPropDirectReadPeer(); + void complexPropDirectWritePeer(); + void getVoidSignal_data(); void getVoidSignal(); void getStringSignal_data(); @@ -103,16 +146,31 @@ private slots: void getComplexSignal_data(); void getComplexSignal(); + void getVoidSignalPeer_data(); + void getVoidSignalPeer(); + void getStringSignalPeer_data(); + void getStringSignalPeer(); + void getComplexSignalPeer_data(); + void getComplexSignalPeer(); + void followSignal(); void createErrors_data(); void createErrors(); + void createErrorsPeer_data(); + void createErrorsPeer(); + void callErrors_data(); void callErrors(); void asyncCallErrors_data(); void asyncCallErrors(); + void callErrorsPeer_data(); + void callErrorsPeer(); + void asyncCallErrorsPeer_data(); + void asyncCallErrorsPeer(); + void propertyReadErrors_data(); void propertyReadErrors(); void propertyWriteErrors_data(); @@ -121,8 +179,53 @@ private slots: void directPropertyReadErrors(); void directPropertyWriteErrors_data(); void directPropertyWriteErrors(); + + void propertyReadErrorsPeer_data(); + void propertyReadErrorsPeer(); + void propertyWriteErrorsPeer_data(); + void propertyWriteErrorsPeer(); + void directPropertyReadErrorsPeer_data(); + void directPropertyReadErrorsPeer(); + void directPropertyWriteErrorsPeer_data(); + void directPropertyWriteErrorsPeer(); +private: + QProcess proc; +}; + +class WaitForQPinger: public QObject +{ + Q_OBJECT +public: + WaitForQPinger(); + bool ok(); +public Q_SLOTS: + void ownerChange(const QString &name) + { + if (name == serviceName) + loop.quit(); + } + +private: + QEventLoop loop; }; +WaitForQPinger::WaitForQPinger() +{ + QDBusConnection con = QDBusConnection::sessionBus(); + if (!ok()) { + connect(con.interface(), SIGNAL(serviceOwnerChanged(QString,QString,QString)), + SLOT(ownerChange(QString))); + QTimer::singleShot(2000, &loop, SLOT(quit())); + loop.exec(); + } +} + +bool WaitForQPinger::ok() +{ + return QDBusConnection::sessionBus().isConnected() && + QDBusConnection::sessionBus().interface()->isServiceRegistered(serviceName); +} + tst_QDBusAbstractInterface::tst_QDBusAbstractInterface() { // register the meta types @@ -139,6 +242,39 @@ void tst_QDBusAbstractInterface::initTestCase() QDBusConnection con = QDBusConnection::sessionBus(); QVERIFY(con.isConnected()); con.registerObject("/", &targetObj, QDBusConnection::ExportScriptableContents); + + // start peer server + #ifdef Q_OS_WIN + proc.start("qpinger"); + #else + proc.start("./qpinger/qpinger"); + #endif + QVERIFY(proc.waitForStarted()); + + WaitForQPinger w; + QVERIFY(w.ok()); + //QTest::qWait(2000); + + // get peer server address + QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "address"); + QDBusMessage rpl = con.call(req); + QVERIFY(rpl.type() == QDBusMessage::ReplyMessage); + QString address = rpl.arguments().at(0).toString(); + + // connect to peer server + QDBusConnection peercon = QDBusConnection::connectToPeer(address, "peer"); + QVERIFY(peercon.isConnected()); + + QDBusMessage req2 = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "isConnected"); + QDBusMessage rpl2 = con.call(req2); + QVERIFY(rpl2.type() == QDBusMessage::ReplyMessage); + QVERIFY(rpl2.arguments().at(0).toBool()); +} + +void tst_QDBusAbstractInterface::cleanupTestCase() +{ + proc.close(); + proc.kill(); } void tst_QDBusAbstractInterface::makeVoidCall() @@ -184,6 +320,49 @@ void tst_QDBusAbstractInterface::makeMultiOutCall() QCOMPARE(value, expectedValue); } +void tst_QDBusAbstractInterface::makeVoidCallPeer() +{ + Pinger p = getPingerPeer(); + QVERIFY2(p, "Not connected to D-Bus"); + + QDBusReply r = p->voidMethod(); + QVERIFY(r.isValid()); +} + +void tst_QDBusAbstractInterface::makeStringCallPeer() +{ + Pinger p = getPingerPeer(); + QVERIFY2(p, "Not connected to D-Bus"); + + QDBusReply r = p->stringMethod(); + QVERIFY(r.isValid()); + QCOMPARE(r.value(), targetObj.stringMethod()); +} + +void tst_QDBusAbstractInterface::makeComplexCallPeer() +{ + Pinger p = getPingerPeer(); + QVERIFY2(p, "Not connected to D-Bus"); + + QDBusReply r = p->complexMethod(); + QVERIFY(r.isValid()); + QCOMPARE(r.value(), targetObj.complexMethod()); +} + +void tst_QDBusAbstractInterface::makeMultiOutCallPeer() +{ + Pinger p = getPingerPeer(); + QVERIFY2(p, "Not connected to D-Bus"); + + int value; + QDBusReply r = p->multiOutMethod(value); + QVERIFY(r.isValid()); + + int expectedValue; + QCOMPARE(r.value(), targetObj.multiOutMethod(expectedValue)); + QCOMPARE(value, expectedValue); +} + void tst_QDBusAbstractInterface::makeAsyncVoidCall() { Pinger p = getPinger(); @@ -230,6 +409,55 @@ void tst_QDBusAbstractInterface::makeAsyncMultiOutCall() QCOMPARE(r.argumentAt<1>(), expectedValue); } +void tst_QDBusAbstractInterface::makeAsyncVoidCallPeer() +{ + Pinger p = getPingerPeer(); + QVERIFY2(p, "Not connected to D-Bus"); + + QDBusPendingReply r = p->voidMethod(); + r.waitForFinished(); + QVERIFY(r.isValid()); +} +void tst_QDBusAbstractInterface::makeAsyncStringCallPeer() +{ + Pinger p = getPingerPeer(); + QVERIFY2(p, "Not connected to D-Bus"); + + QDBusMessage reply = p->call(QDBus::BlockWithGui, QLatin1String("voidMethod")); + QVERIFY(reply.type() == QDBusMessage::ReplyMessage); + + QDBusPendingReply r = p->stringMethod(); + r.waitForFinished(); + QVERIFY(r.isValid()); + QCOMPARE(r.value(), targetObj.stringMethod()); +} + +void tst_QDBusAbstractInterface::makeAsyncComplexCallPeer() +{ + Pinger p = getPingerPeer(); + QVERIFY2(p, "Not connected to D-Bus"); + + QDBusPendingReply r = p->complexMethod(); + r.waitForFinished(); + QVERIFY(r.isValid()); + QCOMPARE(r.value(), targetObj.complexMethod()); +} + +void tst_QDBusAbstractInterface::makeAsyncMultiOutCallPeer() +{ + Pinger p = getPingerPeer(); + QVERIFY2(p, "Not connected to D-Bus"); + + QDBusPendingReply r = p->multiOutMethod(); + r.waitForFinished(); + QVERIFY(r.isValid()); + + int expectedValue; + QCOMPARE(r.value(), targetObj.multiOutMethod(expectedValue)); + QCOMPARE(r.argumentAt<1>(), expectedValue); + QCoreApplication::instance()->processEvents(); +} + void tst_QDBusAbstractInterface::stringPropRead() { Pinger p = getPinger(); @@ -295,6 +523,77 @@ void tst_QDBusAbstractInterface::complexPropWrite() QCOMPARE(targetObj.m_complexProp, expectedValue); } +void tst_QDBusAbstractInterface::stringPropReadPeer() +{ + Pinger p = getPingerPeer(); + QVERIFY2(p, "Not connected to D-Bus"); + resetServer(); + + QString expectedValue = "This is a test"; + QVariant v = p->property("stringProp"); + QVERIFY(v.isValid()); + QCOMPARE(v.toString(), expectedValue); +} + +void tst_QDBusAbstractInterface::stringPropWritePeer() +{ + Pinger p = getPingerPeer(); + QVERIFY2(p, "Not connected to D-Bus"); + resetServer(); + + QString expectedValue = "This is a value"; + QVERIFY(p->setProperty("stringProp", expectedValue)); + QCOMPARE(targetObj.m_stringProp, expectedValue); +} + +void tst_QDBusAbstractInterface::variantPropReadPeer() +{ + Pinger p = getPingerPeer(); + QVERIFY2(p, "Not connected to D-Bus"); + resetServer(); + + QDBusVariant expectedValue = QDBusVariant(QVariant(42)); + QVariant v = p->property("variantProp"); + QVERIFY(v.isValid()); + QDBusVariant value = v.value(); + QCOMPARE(value.variant().userType(), expectedValue.variant().userType()); + QCOMPARE(value.variant(), expectedValue.variant()); +} + +void tst_QDBusAbstractInterface::variantPropWritePeer() +{ + Pinger p = getPingerPeer(); + QVERIFY2(p, "Not connected to D-Bus"); + resetServer(); + + QDBusVariant expectedValue = QDBusVariant(Q_INT64_C(-47)); + QVERIFY(p->setProperty("variantProp", qVariantFromValue(expectedValue))); + QCOMPARE(targetObj.m_variantProp.variant(), expectedValue.variant()); +} + +void tst_QDBusAbstractInterface::complexPropReadPeer() +{ + Pinger p = getPingerPeer(); + QVERIFY2(p, "Not connected to D-Bus"); + resetServer(); + + RegisteredType expectedValue = RegisteredType("This is a test"); + QVariant v = p->property("complexProp"); + QVERIFY(v.userType() == qMetaTypeId()); + QCOMPARE(v.value(), expectedValue); +} + +void tst_QDBusAbstractInterface::complexPropWritePeer() +{ + Pinger p = getPingerPeer(); + QVERIFY2(p, "Not connected to D-Bus"); + resetServer(); + + RegisteredType expectedValue = RegisteredType("This is a value"); + QVERIFY(p->setProperty("complexProp", qVariantFromValue(expectedValue))); + QCOMPARE(targetObj.m_complexProp, expectedValue); +} + void tst_QDBusAbstractInterface::stringPropDirectRead() { Pinger p = getPinger(); @@ -353,6 +652,70 @@ void tst_QDBusAbstractInterface::complexPropDirectWrite() QCOMPARE(targetObj.m_complexProp, expectedValue); } +void tst_QDBusAbstractInterface::stringPropDirectReadPeer() +{ + Pinger p = getPingerPeer(); + QVERIFY2(p, "Not connected to D-Bus"); + resetServer(); + + QString expectedValue = "This is a test"; + QCOMPARE(p->stringProp(), expectedValue); +} + +void tst_QDBusAbstractInterface::stringPropDirectWritePeer() +{ + Pinger p = getPingerPeer(); + QVERIFY2(p, "Not connected to D-Bus"); + resetServer(); + + QString expectedValue = "This is a value"; + p->setStringProp(expectedValue); + QCOMPARE(targetObj.m_stringProp, expectedValue); +} + +void tst_QDBusAbstractInterface::variantPropDirectReadPeer() +{ + Pinger p = getPingerPeer(); + QVERIFY2(p, "Not connected to D-Bus"); + resetServer(); + + QDBusVariant expectedValue = QDBusVariant(42); + QCOMPARE(p->variantProp().variant(), expectedValue.variant()); +} + +void tst_QDBusAbstractInterface::variantPropDirectWritePeer() +{ + Pinger p = getPingerPeer(); + QVERIFY2(p, "Not connected to D-Bus"); + resetServer(); + + QDBusVariant expectedValue = QDBusVariant(Q_INT64_C(-47)); + p->setVariantProp(expectedValue); + QCOMPARE(targetObj.m_variantProp.variant().userType(), expectedValue.variant().userType()); + QCOMPARE(targetObj.m_variantProp.variant(), expectedValue.variant()); +} + +void tst_QDBusAbstractInterface::complexPropDirectReadPeer() +{ + Pinger p = getPingerPeer(); + QVERIFY2(p, "Not connected to D-Bus"); + resetServer(); + + RegisteredType expectedValue = RegisteredType("This is a test"); + QCOMPARE(p->complexProp(), expectedValue); +} + +void tst_QDBusAbstractInterface::complexPropDirectWritePeer() +{ + Pinger p = getPingerPeer(); + QVERIFY2(p, "Not connected to D-Bus"); + resetServer(); + + RegisteredType expectedValue = RegisteredType("This is a value"); + p->setComplexProp(expectedValue); + QCOMPARE(targetObj.m_complexProp, expectedValue); +} + void tst_QDBusAbstractInterface::getVoidSignal_data() { QTest::addColumn("service"); @@ -437,6 +800,89 @@ void tst_QDBusAbstractInterface::getComplexSignal() QCOMPARE(s[0][0].value(), expectedValue); } +void tst_QDBusAbstractInterface::getVoidSignalPeer_data() +{ + QTest::addColumn("path"); + + QTest::newRow("specific") << "/"; + QTest::newRow("wildcard") << QString(); +} + +void tst_QDBusAbstractInterface::getVoidSignalPeer() +{ + QFETCH(QString, path); + Pinger p = getPingerPeer(path); + QVERIFY2(p, "Not connected to D-Bus"); + + // we need to connect the signal somewhere in order for D-Bus to enable the rules + QTestEventLoop::instance().connect(p.data(), SIGNAL(voidSignal()), SLOT(exitLoop())); + QSignalSpy s(p.data(), SIGNAL(voidSignal())); + + QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "voidSignal"); + QVERIFY(QDBusConnection::sessionBus().send(req)); + QTestEventLoop::instance().enterLoop(2); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QVERIFY(s.size() == 1); + QVERIFY(s.at(0).size() == 0); +} + +void tst_QDBusAbstractInterface::getStringSignalPeer_data() +{ + getVoidSignalPeer_data(); +} + +void tst_QDBusAbstractInterface::getStringSignalPeer() +{ + QFETCH(QString, path); + Pinger p = getPingerPeer(path); + QVERIFY2(p, "Not connected to D-Bus"); + + // we need to connect the signal somewhere in order for D-Bus to enable the rules + QTestEventLoop::instance().connect(p.data(), SIGNAL(stringSignal(QString)), SLOT(exitLoop())); + QSignalSpy s(p.data(), SIGNAL(stringSignal(QString))); + + QString expectedValue = "Good morning"; + QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "stringSignal"); + req << expectedValue; + QVERIFY(QDBusConnection::sessionBus().send(req)); + QTestEventLoop::instance().enterLoop(2); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QVERIFY(s.size() == 1); + QVERIFY(s[0].size() == 1); + QCOMPARE(s[0][0].userType(), int(QVariant::String)); + QCOMPARE(s[0][0].toString(), expectedValue); +} + +void tst_QDBusAbstractInterface::getComplexSignalPeer_data() +{ + getVoidSignalPeer_data(); +} + +void tst_QDBusAbstractInterface::getComplexSignalPeer() +{ + QFETCH(QString, path); + Pinger p = getPingerPeer(path); + QVERIFY2(p, "Not connected to D-Bus"); + + // we need to connect the signal somewhere in order for D-Bus to enable the rules + QTestEventLoop::instance().connect(p.data(), SIGNAL(complexSignal(RegisteredType)), SLOT(exitLoop())); + QSignalSpy s(p.data(), SIGNAL(complexSignal(RegisteredType))); + + RegisteredType expectedValue("Good evening"); + QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "complexSignal"); + req << "Good evening"; + QVERIFY(QDBusConnection::sessionBus().send(req)); + QTestEventLoop::instance().enterLoop(2); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QVERIFY(s.size() == 1); + QVERIFY(s[0].size() == 1); + QCOMPARE(s[0][0].userType(), qMetaTypeId()); + QCOMPARE(s[0][0].value(), expectedValue); +} + void tst_QDBusAbstractInterface::followSignal() { const QString serviceToFollow = "com.trolltech.tst_qdbusabstractinterface.FollowMe"; @@ -514,6 +960,24 @@ void tst_QDBusAbstractInterface::createErrors() QTEST(p->lastError().name(), "errorName"); } +void tst_QDBusAbstractInterface::createErrorsPeer_data() +{ + QTest::addColumn("path"); + QTest::addColumn("errorName"); + + QTest::newRow("invalid-path") << "this isn't valid" << "com.trolltech.QtDBus.Error.InvalidObjectPath"; +} + +void tst_QDBusAbstractInterface::createErrorsPeer() +{ + QFETCH(QString, path); + Pinger p = getPingerPeer(path); + QVERIFY2(p, "Not connected to D-Bus"); + + QVERIFY(!p->isValid()); + QTEST(p->lastError().name(), "errorName"); +} + void tst_QDBusAbstractInterface::callErrors_data() { createErrors_data(); @@ -556,6 +1020,43 @@ void tst_QDBusAbstractInterface::asyncCallErrors() QCOMPARE(p->lastError().name(), r.error().name()); } +void tst_QDBusAbstractInterface::callErrorsPeer_data() +{ + createErrorsPeer_data(); + QTest::newRow("path-wildcard") << QString() << "com.trolltech.QtDBus.Error.InvalidObjectPath"; +} + +void tst_QDBusAbstractInterface::callErrorsPeer() +{ + QFETCH(QString, path); + Pinger p = getPingerPeer(path); + QVERIFY2(p, "Not connected to D-Bus"); + + // we shouldn't be able to make this call: + QDBusReply r = p->stringMethod(); + QVERIFY(!r.isValid()); + QTEST(r.error().name(), "errorName"); + QCOMPARE(p->lastError().name(), r.error().name()); +} + +void tst_QDBusAbstractInterface::asyncCallErrorsPeer_data() +{ + callErrorsPeer_data(); +} + +void tst_QDBusAbstractInterface::asyncCallErrorsPeer() +{ + QFETCH(QString, path); + Pinger p = getPingerPeer(path); + QVERIFY2(p, "Not connected to D-Bus"); + + // we shouldn't be able to make this call: + QDBusPendingReply r = p->stringMethod(); + QVERIFY(r.isError()); + QTEST(r.error().name(), "errorName"); + QCOMPARE(p->lastError().name(), r.error().name()); +} + void tst_QDBusAbstractInterface::propertyReadErrors_data() { callErrors_data(); @@ -632,5 +1133,77 @@ void tst_QDBusAbstractInterface::directPropertyWriteErrors() QTEST(p->lastError().name(), "errorName"); } +void tst_QDBusAbstractInterface::propertyReadErrorsPeer_data() +{ + callErrorsPeer_data(); +} + +void tst_QDBusAbstractInterface::propertyReadErrorsPeer() +{ + QFETCH(QString, path); + Pinger p = getPingerPeer(path); + QVERIFY2(p, "Not connected to D-Bus"); + + // we shouldn't be able to get this value: + QVariant v = p->property("stringProp"); + QVERIFY(v.isNull()); + QVERIFY(!v.isValid()); + QTEST(p->lastError().name(), "errorName"); +} + +void tst_QDBusAbstractInterface::propertyWriteErrorsPeer_data() +{ + callErrorsPeer_data(); +} + +void tst_QDBusAbstractInterface::propertyWriteErrorsPeer() +{ + QFETCH(QString, path); + Pinger p = getPingerPeer(path); + QVERIFY2(p, "Not connected to D-Bus"); + + // we shouldn't be able to get this value: + if (p->isValid()) + QCOMPARE(int(p->lastError().type()), int(QDBusError::NoError)); + QVERIFY(!p->setProperty("stringProp", "")); + QTEST(p->lastError().name(), "errorName"); +} + +void tst_QDBusAbstractInterface::directPropertyReadErrorsPeer_data() +{ + callErrorsPeer_data(); +} + +void tst_QDBusAbstractInterface::directPropertyReadErrorsPeer() +{ + QFETCH(QString, path); + Pinger p = getPingerPeer(path); + QVERIFY2(p, "Not connected to D-Bus"); + + // we shouldn't be able to get this value: + QString v = p->stringProp(); + QVERIFY(v.isNull()); + QTEST(p->lastError().name(), "errorName"); +} + +void tst_QDBusAbstractInterface::directPropertyWriteErrorsPeer_data() +{ + callErrorsPeer_data(); +} + +void tst_QDBusAbstractInterface::directPropertyWriteErrorsPeer() +{ + QFETCH(QString, path); + Pinger p = getPingerPeer(path); + QVERIFY2(p, "Not connected to D-Bus"); + + // we shouldn't be able to get this value: + // but there's no direct way of verifying that the setting failed + if (p->isValid()) + QCOMPARE(int(p->lastError().type()), int(QDBusError::NoError)); + p->setStringProp(""); + QTEST(p->lastError().name(), "errorName"); +} + QTEST_MAIN(tst_QDBusAbstractInterface) #include "tst_qdbusabstractinterface.moc" -- cgit v0.12 From 6d032e84de8238e555a191b04311ed6a811ddd87 Mon Sep 17 00:00:00 2001 From: "Daniele E. Domenichelli" Date: Mon, 18 Apr 2011 11:21:17 -0500 Subject: QtDBus: Add unit tests for QDBusInterface Merge-request: 2343 Reviewed-by: Marius Storm-Olsen Reviewed-by: Thiago Macieira --- tests/auto/qdbusinterface/myobject.h | 164 ++++++ tests/auto/qdbusinterface/qdbusinterface.pro | 7 +- tests/auto/qdbusinterface/qmyserver/qmyserver.cpp | 155 ++++++ tests/auto/qdbusinterface/qmyserver/qmyserver.pro | 5 + tests/auto/qdbusinterface/test/test.pro | 7 + tests/auto/qdbusinterface/tst_qdbusinterface.cpp | 613 ++++++++++++++++++---- 6 files changed, 832 insertions(+), 119 deletions(-) create mode 100644 tests/auto/qdbusinterface/myobject.h create mode 100644 tests/auto/qdbusinterface/qmyserver/qmyserver.cpp create mode 100644 tests/auto/qdbusinterface/qmyserver/qmyserver.pro create mode 100644 tests/auto/qdbusinterface/test/test.pro diff --git a/tests/auto/qdbusinterface/myobject.h b/tests/auto/qdbusinterface/myobject.h new file mode 100644 index 0000000..68b8d1a --- /dev/null +++ b/tests/auto/qdbusinterface/myobject.h @@ -0,0 +1,164 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite 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$ +** +****************************************************************************/ + +#ifndef MYOBJECT_H +#define MYOBJECT_H + +#include +#include + +Q_DECLARE_METATYPE(QVariantList) + +class MyObject: public QObject +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "com.trolltech.QtDBus.MyObject") + Q_CLASSINFO("D-Bus Introspection", "" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" +" \n" + "") + Q_PROPERTY(int prop1 READ prop1 WRITE setProp1) + Q_PROPERTY(QList complexProp READ complexProp WRITE setComplexProp) + +public: + static int callCount; + static QVariantList callArgs; + MyObject() + { + QObject *subObject = new QObject(this); + subObject->setObjectName("subObject"); + } + + int m_prop1; + int prop1() const + { + ++callCount; + return m_prop1; + } + void setProp1(int value) + { + ++callCount; + m_prop1 = value; + } + + QList m_complexProp; + QList complexProp() const + { + ++callCount; + return m_complexProp; + } + void setComplexProp(const QList &value) + { + ++callCount; + m_complexProp = value; + } + + Q_INVOKABLE void ping_invokable(QDBusMessage msg) + { + QDBusConnection sender = QDBusConnection::sender(); + if (!sender.isConnected()) + exit(1); + + ++callCount; + callArgs = msg.arguments(); + + msg.setDelayedReply(true); + if (!sender.send(msg.createReply(callArgs))) + exit(1); + } + +public slots: + + void ping(QDBusMessage msg) + { + QDBusConnection sender = QDBusConnection::sender(); + if (!sender.isConnected()) + exit(1); + + ++callCount; + callArgs = msg.arguments(); + + msg.setDelayedReply(true); + if (!sender.send(msg.createReply(callArgs))) + exit(1); + } +}; + +#endif // INTERFACE_H diff --git a/tests/auto/qdbusinterface/qdbusinterface.pro b/tests/auto/qdbusinterface/qdbusinterface.pro index ac14ab7..0aca06c 100644 --- a/tests/auto/qdbusinterface/qdbusinterface.pro +++ b/tests/auto/qdbusinterface/qdbusinterface.pro @@ -1,10 +1,11 @@ load(qttest_p4) QT = core contains(QT_CONFIG,dbus): { - SOURCES += tst_qdbusinterface.cpp - QT += dbus + TEMPLATE = subdirs + CONFIG += ordered + SUBDIRS = qmyserver test } else { - SOURCES += ../qdbusmarshall/dummy.cpp + SOURCES += ../qdbusmarshall/dummy.cpp } diff --git a/tests/auto/qdbusinterface/qmyserver/qmyserver.cpp b/tests/auto/qdbusinterface/qmyserver/qmyserver.cpp new file mode 100644 index 0000000..c68f7bf --- /dev/null +++ b/tests/auto/qdbusinterface/qmyserver/qmyserver.cpp @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite 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 +#include + +#include "../myobject.h" + +static const char serviceName[] = "com.trolltech.autotests.qmyserver"; +static const char objectPath[] = "/com/trolltech/qmyserver"; +//static const char *interfaceName = serviceName; + +int MyObject::callCount = 0; +QVariantList MyObject::callArgs; + +class MyServer : public QDBusServer +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "com.trolltech.autotests.qmyserver") + +public: + MyServer(QString addr = "unix:tmpdir=/tmp", QObject* parent = 0) + : QDBusServer(addr, parent), + m_conn("none") + { + connect(this, SIGNAL(newConnection(const QDBusConnection&)), SLOT(handleConnection(const QDBusConnection&))); + } + +public slots: + QString address() const + { + return QDBusServer::address(); + } + + bool isConnected() const + { + return m_conn.isConnected(); + } + + void emitSignal(const QString &interface, const QString &name, const QString &arg) + { + QDBusMessage msg = QDBusMessage::createSignal("/", interface, name); + msg << arg; + m_conn.send(msg); + } + + void reset() + { + MyObject::callCount = 0; + obj.m_complexProp.clear(); + } + + int callCount() + { + return MyObject::callCount; + } + + QVariantList callArgs() + { + qDebug() << "callArgs" << MyObject::callArgs.count(); + return MyObject::callArgs; + } + + void setProp1(int val) + { + obj.m_prop1 = val; + } + + int prop1() + { + return obj.m_prop1; + } + + void setComplexProp(QList val) + { + obj.m_complexProp = val; + } + + QList complexProp() + { + return obj.m_complexProp; + } + + +private slots: + void handleConnection(const QDBusConnection& con) + { + m_conn = con; + m_conn.registerObject("/", &obj, QDBusConnection::ExportAllProperties + | QDBusConnection::ExportAllSlots + | QDBusConnection::ExportAllInvokables); + } + +private: + QDBusConnection m_conn; + MyObject obj; +}; + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + + QDBusConnection con = QDBusConnection::sessionBus(); + if (!con.isConnected()) + exit(1); + + if (!con.registerService(serviceName)) + exit(2); + + MyServer server; + con.registerObject(objectPath, &server, QDBusConnection::ExportAllSlots); + + printf("ready.\n"); + + return app.exec(); +} + +#include "qmyserver.moc" \ No newline at end of file diff --git a/tests/auto/qdbusinterface/qmyserver/qmyserver.pro b/tests/auto/qdbusinterface/qmyserver/qmyserver.pro new file mode 100644 index 0000000..f4fe02c --- /dev/null +++ b/tests/auto/qdbusinterface/qmyserver/qmyserver.pro @@ -0,0 +1,5 @@ +SOURCES = qmyserver.cpp +HEADERS = ../myobject.h +TARGET = qmyserver +QT += dbus +QT -= gui diff --git a/tests/auto/qdbusinterface/test/test.pro b/tests/auto/qdbusinterface/test/test.pro new file mode 100644 index 0000000..3252188 --- /dev/null +++ b/tests/auto/qdbusinterface/test/test.pro @@ -0,0 +1,7 @@ +load(qttest_p4) +SOURCES += ../tst_qdbusinterface.cpp +HEADERS += ../myobject.h +TARGET = ../tst_qdbusinterface + +QT = core +QT += dbus diff --git a/tests/auto/qdbusinterface/tst_qdbusinterface.cpp b/tests/auto/qdbusinterface/tst_qdbusinterface.cpp index ce11459..04b3d72 100644 --- a/tests/auto/qdbusinterface/tst_qdbusinterface.cpp +++ b/tests/auto/qdbusinterface/tst_qdbusinterface.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ /* -*- C++ -*- */ + #include #include #include @@ -47,125 +48,15 @@ #include #include "../qdbusmarshall/common.h" - -Q_DECLARE_METATYPE(QVariantList) +#include "myobject.h" #define TEST_INTERFACE_NAME "com.trolltech.QtDBus.MyObject" #define TEST_SIGNAL_NAME "somethingHappened" -class MyObject: public QObject -{ - Q_OBJECT - Q_CLASSINFO("D-Bus Interface", "com.trolltech.QtDBus.MyObject") - Q_CLASSINFO("D-Bus Introspection", "" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" -" \n" - "") - Q_PROPERTY(int prop1 READ prop1 WRITE setProp1) - Q_PROPERTY(QList complexProp READ complexProp WRITE setComplexProp) - -public: - static int callCount; - static QVariantList callArgs; - MyObject() - { - QObject *subObject = new QObject(this); - subObject->setObjectName("subObject"); - } - - int m_prop1; - int prop1() const - { - ++callCount; - return m_prop1; - } - void setProp1(int value) - { - ++callCount; - m_prop1 = value; - } - - QList m_complexProp; - QList complexProp() const - { - ++callCount; - return m_complexProp; - } - void setComplexProp(const QList &value) - { - ++callCount; - m_complexProp = value; - } - - Q_INVOKABLE void ping_invokable(QDBusMessage msg) - { - QDBusConnection sender = QDBusConnection::sender(); - if (!sender.isConnected()) - exit(1); - - ++callCount; - callArgs = msg.arguments(); - - msg.setDelayedReply(true); - if (!sender.send(msg.createReply(callArgs))) - exit(1); - } - -public slots: - - void ping(QDBusMessage msg) - { - QDBusConnection sender = QDBusConnection::sender(); - if (!sender.isConnected()) - exit(1); - - ++callCount; - callArgs = msg.arguments(); +static const char serviceName[] = "com.trolltech.autotests.qmyserver"; +static const char objectPath[] = "/com/trolltech/qmyserver"; +static const char *interfaceName = serviceName; - msg.setDelayedReply(true); - if (!sender.send(msg.createReply(callArgs))) - exit(1); - } -}; int MyObject::callCount = 0; QVariantList MyObject::callArgs; @@ -228,10 +119,70 @@ void emitSignal(const QString &interface, const QString &name, const QString &ar QTest::qWait(1000); } +void emitSignalPeer(const QString &interface, const QString &name, const QString &arg) +{ + QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "emitSignal"); + req << interface; + req << name; + req << arg; + QDBusConnection::sessionBus().send(req); + + QTest::qWait(1000); +} + +int callCountPeer() +{ + QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "callCount"); + QDBusMessage reply = QDBusConnection::sessionBus().call(req); + return reply.arguments().at(0).toInt(); +} + +QVariantList callArgsPeer() +{ + QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "callArgs"); + QDBusMessage reply = QDBusConnection::sessionBus().call(req); + return qdbus_cast(reply.arguments().at(0)); +} + +void setProp1Peer(int val) +{ + QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "setProp1"); + req << val; + QDBusMessage reply = QDBusConnection::sessionBus().call(req); +} + +int prop1Peer() +{ + QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "prop1"); + QDBusMessage reply = QDBusConnection::sessionBus().call(req); + return reply.arguments().at(0).toInt(); +} + +void setComplexPropPeer(QList val) +{ + QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "setComplexProp"); + req << qVariantFromValue(val); + QDBusMessage reply = QDBusConnection::sessionBus().call(req); +} + +QList complexPropPeer() +{ + QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "complexProp"); + QDBusMessage reply = QDBusConnection::sessionBus().call(req); + return qdbus_cast >(reply.arguments().at(0)); +} + +void resetPeer() +{ + QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "reset"); + QDBusConnection::sessionBus().call(req); +} + class tst_QDBusInterface: public QObject { Q_OBJECT MyObject obj; + public slots: void testServiceOwnerChanged(const QString &service) { @@ -241,6 +192,7 @@ public slots: private slots: void initTestCase(); + void cleanupTestCase(); void notConnected(); void notValid(); @@ -254,14 +206,63 @@ private slots: void invokeMethodWithMultiReturn(); void invokeMethodWithComplexReturn(); + void introspectPeer(); + void callMethodPeer(); + void invokeMethodPeer(); + void invokeMethodWithReturnPeer(); + void invokeMethodWithMultiReturnPeer(); + void invokeMethodWithComplexReturnPeer(); + void signal(); + void signalPeer(); void propertyRead(); void propertyWrite(); void complexPropertyRead(); void complexPropertyWrite(); + + void propertyReadPeer(); + void propertyWritePeer(); + void complexPropertyReadPeer(); + void complexPropertyWritePeer(); +private: + QProcess proc; }; +class WaitForQMyServer: public QObject +{ + Q_OBJECT +public: + WaitForQMyServer(); + bool ok(); +public Q_SLOTS: + void ownerChange(const QString &name) + { + if (name == serviceName) + loop.quit(); + } + +private: + QEventLoop loop; +}; + +WaitForQMyServer::WaitForQMyServer() +{ + QDBusConnection con = QDBusConnection::sessionBus(); + if (!ok()) { + connect(con.interface(), SIGNAL(serviceOwnerChanged(QString,QString,QString)), + SLOT(ownerChange(QString))); + QTimer::singleShot(2000, &loop, SLOT(quit())); + loop.exec(); + } +} + +bool WaitForQMyServer::ok() +{ + return QDBusConnection::sessionBus().isConnected() && + QDBusConnection::sessionBus().interface()->isServiceRegistered(serviceName); +} + void tst_QDBusInterface::initTestCase() { QDBusConnection con = QDBusConnection::sessionBus(); @@ -271,6 +272,39 @@ void tst_QDBusInterface::initTestCase() con.registerObject("/", &obj, QDBusConnection::ExportAllProperties | QDBusConnection::ExportAllSlots | QDBusConnection::ExportAllInvokables); + + // start peer server + #ifdef Q_OS_WIN + proc.start("qmyserver"); + #else + proc.start("./qmyserver/qmyserver"); + #endif + QVERIFY(proc.waitForStarted()); + + WaitForQMyServer w; + QVERIFY(w.ok()); + //QTest::qWait(2000); + + // get peer server address + QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "address"); + QDBusMessage rpl = con.call(req); + QVERIFY(rpl.type() == QDBusMessage::ReplyMessage); + QString address = rpl.arguments().at(0).toString(); + + // connect to peer server + QDBusConnection peercon = QDBusConnection::connectToPeer(address, "peer"); + QVERIFY(peercon.isConnected()); + + QDBusMessage req2 = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "isConnected"); + QDBusMessage rpl2 = con.call(req2); + QVERIFY(rpl2.type() == QDBusMessage::ReplyMessage); + QVERIFY(rpl2.arguments().at(0).toBool()); +} + +void tst_QDBusInterface::cleanupTestCase() +{ + proc.close(); + proc.kill(); } void tst_QDBusInterface::notConnected() @@ -564,7 +598,7 @@ void tst_QDBusInterface::invokeMethodWithComplexReturn() // verify that we got the reply as expected QCOMPARE(retArg, arg); - + // make the INVOKABLE call without a return type QList arg2 = QList() << 24 << -74; QVERIFY(QMetaObject::invokeMethod(&iface, "ping", Q_RETURN_ARG(QList, retArg), Q_ARG(QList, arg2))); @@ -580,6 +614,250 @@ void tst_QDBusInterface::invokeMethodWithComplexReturn() QCOMPARE(retArg, arg2); } +void tst_QDBusInterface::introspectPeer() +{ + QDBusConnection con("peer"); + QDBusInterface iface(QString(), QLatin1String("/"), + TEST_INTERFACE_NAME, con); + + const QMetaObject *mo = iface.metaObject(); + + QCOMPARE(mo->methodCount() - mo->methodOffset(), 7); + QVERIFY(mo->indexOfSignal(TEST_SIGNAL_NAME "(QString)") != -1); + + QCOMPARE(mo->propertyCount() - mo->propertyOffset(), 2); + QVERIFY(mo->indexOfProperty("prop1") != -1); + QVERIFY(mo->indexOfProperty("complexProp") != -1); +} + +void tst_QDBusInterface::callMethodPeer() +{ + QDBusConnection con("peer"); + QDBusInterface iface(QString(), QLatin1String("/"), + TEST_INTERFACE_NAME, con); + + resetPeer(); + + // call a SLOT method + QDBusMessage reply = iface.call("ping", qVariantFromValue(QDBusVariant("foo"))); + QCOMPARE(callCountPeer(), 1); + QCOMPARE(reply.type(), QDBusMessage::ReplyMessage); + + // verify what the callee received + QVariantList callArgs = callArgsPeer(); + QCOMPARE(callArgs.count(), 1); + QVariant v = callArgs.at(0); + QDBusVariant dv = qdbus_cast(v); + QCOMPARE(dv.variant().type(), QVariant::String); + QCOMPARE(dv.variant().toString(), QString("foo")); + + // verify reply + QCOMPARE(reply.arguments().count(), 1); + v = reply.arguments().at(0); + dv = qdbus_cast(v); + QCOMPARE(dv.variant().type(), QVariant::String); + QCOMPARE(dv.variant().toString(), QString("foo")); + + // call an INVOKABLE method + reply = iface.call("ping_invokable", qVariantFromValue(QDBusVariant("bar"))); + QCOMPARE(callCountPeer(), 2); + QCOMPARE(reply.type(), QDBusMessage::ReplyMessage); + + // verify what the callee received + callArgs = callArgsPeer(); + QCOMPARE(callArgs.count(), 1); + v = callArgs.at(0); + dv = qdbus_cast(v); + QCOMPARE(dv.variant().type(), QVariant::String); + QCOMPARE(dv.variant().toString(), QString("bar")); + + // verify reply + QCOMPARE(reply.arguments().count(), 1); + v = reply.arguments().at(0); + dv = qdbus_cast(v); + QCOMPARE(dv.variant().type(), QVariant::String); + QCOMPARE(dv.variant().toString(), QString("bar")); +} + +void tst_QDBusInterface::invokeMethodPeer() +{ + QDBusConnection con("peer"); + QDBusInterface iface(QString(), QLatin1String("/"), + TEST_INTERFACE_NAME, con); + + resetPeer(); + + // make the SLOT call without a return type + QDBusVariant arg("foo"); + QVERIFY(QMetaObject::invokeMethod(&iface, "ping", Q_ARG(QDBusVariant, arg))); + QCOMPARE(callCountPeer(), 1); + + // verify what the callee received + QVariantList callArgs = callArgsPeer(); + QCOMPARE(callArgs.count(), 1); + QVariant v = callArgs.at(0); + QDBusVariant dv = qdbus_cast(v); + QCOMPARE(dv.variant().type(), QVariant::String); + QCOMPARE(dv.variant().toString(), QString("foo")); + + // make the INVOKABLE call without a return type + QDBusVariant arg2("bar"); + QVERIFY(QMetaObject::invokeMethod(&iface, "ping_invokable", Q_ARG(QDBusVariant, arg2))); + QCOMPARE(callCountPeer(), 2); + + // verify what the callee received + callArgs = callArgsPeer(); + QCOMPARE(callArgs.count(), 1); + v = callArgs.at(0); + dv = qdbus_cast(v); + QCOMPARE(dv.variant().type(), QVariant::String); + QCOMPARE(dv.variant().toString(), QString("bar")); +} + +void tst_QDBusInterface::invokeMethodWithReturnPeer() +{ + QDBusConnection con("peer"); + QDBusInterface iface(QString(), QLatin1String("/"), + TEST_INTERFACE_NAME, con); + + resetPeer(); + QDBusVariant retArg; + + // make the SLOT call without a return type + QDBusVariant arg("foo"); + QVERIFY(QMetaObject::invokeMethod(&iface, "ping", Q_RETURN_ARG(QDBusVariant, retArg), Q_ARG(QDBusVariant, arg))); + QCOMPARE(callCountPeer(), 1); + + // verify what the callee received + QVariantList callArgs = callArgsPeer(); + QCOMPARE(callArgs.count(), 1); + QVariant v = callArgs.at(0); + QDBusVariant dv = qdbus_cast(v); + QCOMPARE(dv.variant().type(), QVariant::String); + QCOMPARE(dv.variant().toString(), arg.variant().toString()); + + // verify that we got the reply as expected + QCOMPARE(retArg.variant(), arg.variant()); + + // make the INVOKABLE call without a return type + QDBusVariant arg2("bar"); + QVERIFY(QMetaObject::invokeMethod(&iface, "ping_invokable", Q_RETURN_ARG(QDBusVariant, retArg), Q_ARG(QDBusVariant, arg2))); + QCOMPARE(callCountPeer(), 2); + + // verify what the callee received + callArgs = callArgsPeer(); + QCOMPARE(callArgs.count(), 1); + v = callArgs.at(0); + dv = qdbus_cast(v); + QCOMPARE(dv.variant().type(), QVariant::String); + QCOMPARE(dv.variant().toString(), arg2.variant().toString()); + + // verify that we got the reply as expected + QCOMPARE(retArg.variant(), arg2.variant()); +} + +void tst_QDBusInterface::invokeMethodWithMultiReturnPeer() +{ + QDBusConnection con("peer"); + QDBusInterface iface(QString(), QLatin1String("/"), + TEST_INTERFACE_NAME, con); + + resetPeer(); + QDBusVariant retArg, retArg2; + + // make the SLOT call without a return type + QDBusVariant arg("foo"), arg2("bar"); + QVERIFY(QMetaObject::invokeMethod(&iface, "ping", + Q_RETURN_ARG(QDBusVariant, retArg), + Q_ARG(QDBusVariant, arg), + Q_ARG(QDBusVariant, arg2), + Q_ARG(QDBusVariant&, retArg2))); + QCOMPARE(callCountPeer(), 1); + + // verify what the callee received + QVariantList callArgs = callArgsPeer(); + QCOMPARE(callArgs.count(), 2); + QVariant v = callArgs.at(0); + QDBusVariant dv = qdbus_cast(v); + QCOMPARE(dv.variant().type(), QVariant::String); + QCOMPARE(dv.variant().toString(), arg.variant().toString()); + + v = callArgs.at(1); + dv = qdbus_cast(v); + QCOMPARE(dv.variant().type(), QVariant::String); + QCOMPARE(dv.variant().toString(), arg2.variant().toString()); + + // verify that we got the replies as expected + QCOMPARE(retArg.variant(), arg.variant()); + QCOMPARE(retArg2.variant(), arg2.variant()); + + // make the INVOKABLE call without a return type + QDBusVariant arg3("hello"), arg4("world"); + QVERIFY(QMetaObject::invokeMethod(&iface, "ping_invokable", + Q_RETURN_ARG(QDBusVariant, retArg), + Q_ARG(QDBusVariant, arg3), + Q_ARG(QDBusVariant, arg4), + Q_ARG(QDBusVariant&, retArg2))); + QCOMPARE(callCountPeer(), 2); + + // verify what the callee received + callArgs = callArgsPeer(); + QCOMPARE(callArgs.count(), 2); + v = callArgs.at(0); + dv = qdbus_cast(v); + QCOMPARE(dv.variant().type(), QVariant::String); + QCOMPARE(dv.variant().toString(), arg3.variant().toString()); + + v = callArgs.at(1); + dv = qdbus_cast(v); + QCOMPARE(dv.variant().type(), QVariant::String); + QCOMPARE(dv.variant().toString(), arg4.variant().toString()); + + // verify that we got the replies as expected + QCOMPARE(retArg.variant(), arg3.variant()); + QCOMPARE(retArg2.variant(), arg4.variant()); +} + +void tst_QDBusInterface::invokeMethodWithComplexReturnPeer() +{ + QDBusConnection con("peer"); + QDBusInterface iface(QString(), QLatin1String("/"), + TEST_INTERFACE_NAME, con); + + resetPeer(); + QList retArg; + + // make the SLOT call without a return type + QList arg = QList() << 42 << -47; + QVERIFY(QMetaObject::invokeMethod(&iface, "ping", Q_RETURN_ARG(QList, retArg), Q_ARG(QList, arg))); + QCOMPARE(callCountPeer(), 1); + + // verify what the callee received + QVariantList callArgs = callArgsPeer(); + QCOMPARE(callArgs.count(), 1); + QVariant v = callArgs.at(0); + QCOMPARE(v.userType(), qMetaTypeId()); + QCOMPARE(qdbus_cast >(v), arg); + + // verify that we got the reply as expected + QCOMPARE(retArg, arg); + + // make the INVOKABLE call without a return type + QList arg2 = QList() << 24 << -74; + QVERIFY(QMetaObject::invokeMethod(&iface, "ping", Q_RETURN_ARG(QList, retArg), Q_ARG(QList, arg2))); + QCOMPARE(callCountPeer(), 2); + + // verify what the callee received + callArgs = callArgsPeer(); + QCOMPARE(callArgs.count(), 1); + v = callArgs.at(0); + QCOMPARE(v.userType(), qMetaTypeId()); + QCOMPARE(qdbus_cast >(v), arg2); + + // verify that we got the reply as expected + QCOMPARE(retArg, arg2); +} + void tst_QDBusInterface::signal() { QDBusConnection con = QDBusConnection::sessionBus(); @@ -621,6 +899,47 @@ void tst_QDBusInterface::signal() } } +void tst_QDBusInterface::signalPeer() +{ + QDBusConnection con("peer"); + QDBusInterface iface(QString(), QLatin1String("/"), + TEST_INTERFACE_NAME, con); + + QString arg = "So long and thanks for all the fish"; + { + Spy spy; + spy.connect(&iface, SIGNAL(somethingHappened(QString)), SLOT(spySlot(QString))); + + emitSignalPeer(TEST_INTERFACE_NAME, TEST_SIGNAL_NAME, arg); + QCOMPARE(spy.count, 1); + QCOMPARE(spy.received, arg); + } + + QDBusInterface iface2(QString(), QLatin1String("/"), + TEST_INTERFACE_NAME, con); + { + Spy spy; + spy.connect(&iface, SIGNAL(somethingHappened(QString)), SLOT(spySlot(QString))); + spy.connect(&iface2, SIGNAL(somethingHappened(QString)), SLOT(spySlot(QString))); + + emitSignalPeer(TEST_INTERFACE_NAME, TEST_SIGNAL_NAME, arg); + QCOMPARE(spy.count, 2); + QCOMPARE(spy.received, arg); + } + + { + Spy spy, spy2; + spy.connect(&iface, SIGNAL(somethingHappened(QString)), SLOT(spySlot(QString))); + spy2.connect(&iface2, SIGNAL(somethingHappened(QString)), SLOT(spySlot(QString))); + + emitSignalPeer(TEST_INTERFACE_NAME, TEST_SIGNAL_NAME, arg); + QCOMPARE(spy.count, 1); + QCOMPARE(spy.received, arg); + QCOMPARE(spy2.count, 1); + QCOMPARE(spy2.received, arg); + } +} + void tst_QDBusInterface::propertyRead() { QDBusConnection con = QDBusConnection::sessionBus(); @@ -683,7 +1002,69 @@ void tst_QDBusInterface::complexPropertyWrite() QCOMPARE(obj.m_complexProp, arg); } +void tst_QDBusInterface::propertyReadPeer() +{ + QDBusConnection con("peer"); + QDBusInterface iface(QString(), QLatin1String("/"), + TEST_INTERFACE_NAME, con); + + resetPeer(); + int arg = 42; + setProp1Peer(42); + + QVariant v = iface.property("prop1"); + QVERIFY(v.isValid()); + QCOMPARE(v.userType(), int(QVariant::Int)); + QCOMPARE(v.toInt(), arg); + QCOMPARE(callCountPeer(), 1); +} + +void tst_QDBusInterface::propertyWritePeer() +{ + QDBusConnection con("peer"); + QDBusInterface iface(QString(), QLatin1String("/"), + TEST_INTERFACE_NAME, con); + + resetPeer(); + int arg = 42; + setProp1Peer(0); + + QVERIFY(iface.setProperty("prop1", arg)); + QCOMPARE(callCountPeer(), 1); + QCOMPARE(prop1Peer(), arg); +} + +void tst_QDBusInterface::complexPropertyReadPeer() +{ + QDBusConnection con("peer"); + QDBusInterface iface(QString(), QLatin1String("/"), + TEST_INTERFACE_NAME, con); + + resetPeer(); + QList arg = QList() << 42 << -47; + setComplexPropPeer(arg); + + QVariant v = iface.property("complexProp"); + QVERIFY(v.isValid()); + QCOMPARE(v.userType(), qMetaTypeId >()); + QCOMPARE(v.value >(), arg); + QCOMPARE(callCountPeer(), 1); +} + +void tst_QDBusInterface::complexPropertyWritePeer() +{ + QDBusConnection con("peer"); + QDBusInterface iface(QString(), QLatin1String("/"), + TEST_INTERFACE_NAME, con); + + resetPeer(); + QList arg = QList() << -47 << 42; + + QVERIFY(iface.setProperty("complexProp", qVariantFromValue(arg))); + QCOMPARE(callCountPeer(), 1); + QCOMPARE(complexPropPeer(), arg); +} + QTEST_MAIN(tst_QDBusInterface) #include "tst_qdbusinterface.moc" - -- cgit v0.12 From 4c8c5ef3866723124fe8cf2c8bdd3b846549b129 Mon Sep 17 00:00:00 2001 From: "Daniele E. Domenichelli" Date: Mon, 18 Apr 2011 11:21:18 -0500 Subject: QtDBus: Add unit tests for QDBusAbstractAdaptor Merge-request: 2343 Reviewed-by: Marius Storm-Olsen Reviewed-by: Thiago Macieira --- tests/auto/qdbusabstractadaptor/myobject.h | 286 +++++ .../qdbusabstractadaptor/qdbusabstractadaptor.pro | 9 +- .../qdbusabstractadaptor/qmyserver/qmyserver.cpp | 167 +++ .../qdbusabstractadaptor/qmyserver/qmyserver.pro | 5 + tests/auto/qdbusabstractadaptor/test/test.pro | 7 + .../tst_qdbusabstractadaptor.cpp | 1091 ++++++++++++++------ 6 files changed, 1240 insertions(+), 325 deletions(-) create mode 100644 tests/auto/qdbusabstractadaptor/myobject.h create mode 100644 tests/auto/qdbusabstractadaptor/qmyserver/qmyserver.cpp create mode 100644 tests/auto/qdbusabstractadaptor/qmyserver/qmyserver.pro create mode 100644 tests/auto/qdbusabstractadaptor/test/test.pro diff --git a/tests/auto/qdbusabstractadaptor/myobject.h b/tests/auto/qdbusabstractadaptor/myobject.h new file mode 100644 index 0000000..7353fa6 --- /dev/null +++ b/tests/auto/qdbusabstractadaptor/myobject.h @@ -0,0 +1,286 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite 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$ +** +****************************************************************************/ + +#ifndef MYOBJECT_H +#define MYOBJECT_H + +#include +#include + +extern const char *slotSpy; +extern QString valueSpy; + +class QDBusSignalSpy: public QObject +{ + Q_OBJECT + +public slots: + void slot(const QDBusMessage &msg) + { + ++count; + interface = msg.interface(); + name = msg.member(); + signature = msg.signature(); + path = msg.path(); + value.clear(); + if (msg.arguments().count()) + value = msg.arguments().at(0); + } + +public: + QDBusSignalSpy() : count(0) { } + + int count; + QString interface; + QString name; + QString signature; + QString path; + QVariant value; +}; + +class Interface1: public QDBusAbstractAdaptor +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "local.Interface1") +public: + Interface1(QObject *parent) : QDBusAbstractAdaptor(parent) + { } +}; + +class Interface2: public QDBusAbstractAdaptor +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "local.Interface2") + Q_PROPERTY(QString prop1 READ prop1) + Q_PROPERTY(QString prop2 READ prop2 WRITE setProp2 SCRIPTABLE true) + Q_PROPERTY(QUrl nonDBusProperty READ nonDBusProperty) +public: + Interface2(QObject *parent) : QDBusAbstractAdaptor(parent) + { setAutoRelaySignals(true); } + + QString prop1() const + { return QLatin1String("QString Interface2::prop1() const"); } + + QString prop2() const + { return QLatin1String("QString Interface2::prop2() const"); } + + void setProp2(const QString &value) + { + slotSpy = "void Interface2::setProp2(const QString &)"; + valueSpy = value; + } + + QUrl nonDBusProperty() const + { return QUrl(); } + + void emitSignal(const QString &, const QVariant &) + { emit signal(); } + +public slots: + void method() + { + slotSpy = "void Interface2::method()"; + } + + Q_SCRIPTABLE void scriptableMethod() + { + slotSpy = "void Interface2::scriptableMethod()"; + } + +signals: + void signal(); +}; + +class Interface3: public QDBusAbstractAdaptor +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "local.Interface3") + Q_PROPERTY(QString prop1 READ prop1) + Q_PROPERTY(QString prop2 READ prop2 WRITE setProp2) + Q_PROPERTY(QString interface3prop READ interface3prop) +public: + Interface3(QObject *parent) : QDBusAbstractAdaptor(parent) + { setAutoRelaySignals(true); } + + QString prop1() const + { return QLatin1String("QString Interface3::prop1() const"); } + + QString prop2() const + { return QLatin1String("QString Interface3::prop2() const"); } + + void setProp2(const QString &value) + { + slotSpy = "void Interface3::setProp2(const QString &)"; + valueSpy = value; + } + + QString interface3prop() const + { return QLatin1String("QString Interface3::interface3prop() const"); } + + void emitSignal(const QString &name, const QVariant &value) + { + if (name == "signalVoid") + emit signalVoid(); + else if (name == "signalInt") + emit signalInt(value.toInt()); + else if (name == "signalString") + emit signalString(value.toString()); + } + +public slots: + void methodVoid() { slotSpy = "void Interface3::methodVoid()"; } + void methodInt(int) { slotSpy = "void Interface3::methodInt(int)"; } + void methodString(QString) { slotSpy = "void Interface3::methodString(QString)"; } + + int methodStringString(const QString &s, QString &out) + { + slotSpy = "int Interface3::methodStringString(const QString &, QString &)"; + out = s; + return 42; + } + +signals: + void signalVoid(); + void signalInt(int); + void signalString(const QString &); +}; + +class Interface4: public QDBusAbstractAdaptor +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "local.Interface4") + Q_PROPERTY(QString prop1 READ prop1) + Q_PROPERTY(QString prop2 READ prop2 WRITE setProp2) + Q_PROPERTY(QString interface4prop READ interface4prop) +public: + Interface4(QObject *parent) : QDBusAbstractAdaptor(parent) + { setAutoRelaySignals(true); } + + QString prop1() const + { return QLatin1String("QString Interface4::prop1() const"); } + + QString prop2() const + { return QLatin1String("QString Interface4::prop2() const"); } + + QString interface4prop() const + { return QLatin1String("QString Interface4::interface4prop() const"); } + + void setProp2(const QString &value) + { + slotSpy = "void Interface4::setProp2(const QString &)"; + valueSpy = value; + } + + void emitSignal(const QString &, const QVariant &value) + { + switch (value.type()) + { + case QVariant::Invalid: + emit signal(); + break; + case QVariant::Int: + emit signal(value.toInt()); + break; + case QVariant::String: + emit signal(value.toString()); + break; + default: + break; + } + } + +public slots: + void method() { slotSpy = "void Interface4::method()"; } + void method(int) { slotSpy = "void Interface4::method(int)"; } + void method(QString) { slotSpy = "void Interface4::method(QString)"; } + +signals: + void signal(); + void signal(int); + void signal(const QString &); +}; + +class MyObject: public QObject +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "local.MyObject") +public: + Interface1 *if1; + Interface2 *if2; + Interface3 *if3; + Interface4 *if4; + + MyObject(int n = 4) + : if1(0), if2(0), if3(0), if4(0) + { + switch (n) + { + case 4: + if4 = new Interface4(this); + case 3: + if3 = new Interface3(this); + case 2: + if2 = new Interface2(this); + case 1: + if1 = new Interface1(this); + } + } + + void emitSignal(const QString &name, const QVariant &value) + { + if (name == "scriptableSignalVoid") + emit scriptableSignalVoid(); + else if (name == "scriptableSignalInt") + emit scriptableSignalInt(value.toInt()); + else if (name == "scriptableSignalString") + emit scriptableSignalString(value.toString()); + else if (name == "nonScriptableSignalVoid") + emit nonScriptableSignalVoid(); + } + +signals: + Q_SCRIPTABLE void scriptableSignalVoid(); + Q_SCRIPTABLE void scriptableSignalInt(int); + Q_SCRIPTABLE void scriptableSignalString(QString); + void nonScriptableSignalVoid(); +}; + +#endif // MYOBJECT_H \ No newline at end of file diff --git a/tests/auto/qdbusabstractadaptor/qdbusabstractadaptor.pro b/tests/auto/qdbusabstractadaptor/qdbusabstractadaptor.pro index 16358c5..c3e3f7f 100644 --- a/tests/auto/qdbusabstractadaptor/qdbusabstractadaptor.pro +++ b/tests/auto/qdbusabstractadaptor/qdbusabstractadaptor.pro @@ -1,10 +1,9 @@ load(qttest_p4) QT = core contains(QT_CONFIG,dbus): { - SOURCES += tst_qdbusabstractadaptor.cpp - QT += dbus + TEMPLATE = subdirs + CONFIG += ordered + SUBDIRS = qmyserver test } else { - SOURCES += ../qdbusmarshall/dummy.cpp + SOURCES += ../qdbusmarshall/dummy.cpp } - - diff --git a/tests/auto/qdbusabstractadaptor/qmyserver/qmyserver.cpp b/tests/auto/qdbusabstractadaptor/qmyserver/qmyserver.cpp new file mode 100644 index 0000000..238bc38 --- /dev/null +++ b/tests/auto/qdbusabstractadaptor/qmyserver/qmyserver.cpp @@ -0,0 +1,167 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite 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 +#include + +#include "../myobject.h" + +static const char serviceName[] = "com.trolltech.autotests.qmyserver"; +static const char objectPath[] = "/com/trolltech/qmyserver"; +//static const char *interfaceName = serviceName; + +const char *slotSpy; +QString valueSpy; + +Q_DECLARE_METATYPE(QDBusConnection::RegisterOptions) + +class MyServer : public QDBusServer +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "com.trolltech.autotests.qmyserver") + +public: + MyServer(QString addr = "unix:tmpdir=/tmp", QObject* parent = 0) + : QDBusServer(addr, parent), + m_conn("none"), + obj(NULL) + { + connect(this, SIGNAL(newConnection(const QDBusConnection&)), SLOT(handleConnection(const QDBusConnection&))); + } + + ~MyServer() + { + if (obj) + obj->deleteLater(); + } + +public slots: + QString address() const + { + return QDBusServer::address(); + } + + bool isConnected() const + { + return m_conn.isConnected(); + } + + void emitSignal(const QString& interface, const QString& name, const QDBusVariant& parameter) + { + if (interface.endsWith('2')) + obj->if2->emitSignal(name, parameter.variant()); + else if (interface.endsWith('3')) + obj->if3->emitSignal(name, parameter.variant()); + else if (interface.endsWith('4')) + obj->if4->emitSignal(name, parameter.variant()); + else + obj->emitSignal(name, parameter.variant()); + } + + void emitSignal2(const QString& interface, const QString& name) + { + if (interface.endsWith('2')) + obj->if2->emitSignal(name, QVariant()); + else if (interface.endsWith('3')) + obj->if3->emitSignal(name, QVariant()); + else if (interface.endsWith('4')) + obj->if4->emitSignal(name, QVariant()); + else + obj->emitSignal(name, QVariant()); + } + + void newMyObject(int nInterfaces = 4) + { + if (obj) + obj->deleteLater(); + obj = new MyObject(nInterfaces); + } + + void registerMyObject(const QString & path, int options) + { + m_conn.registerObject(path, obj, (QDBusConnection::RegisterOptions)options); + } + + QString slotSpyServer() + { + return QLatin1String(slotSpy); + } + + QString valueSpyServer() + { + return valueSpy; + } + + void clearValueSpy() + { + valueSpy.clear(); + } + +private slots: + void handleConnection(const QDBusConnection& con) + { + m_conn = con; + } + +private: + QDBusConnection m_conn; + MyObject* obj; +}; + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + + QDBusConnection con = QDBusConnection::sessionBus(); + if (!con.isConnected()) + exit(1); + + if (!con.registerService(serviceName)) + exit(2); + + MyServer server; + con.registerObject(objectPath, &server, QDBusConnection::ExportAllSlots); + + printf("ready.\n"); + + return app.exec(); +} + +#include "qmyserver.moc" \ No newline at end of file diff --git a/tests/auto/qdbusabstractadaptor/qmyserver/qmyserver.pro b/tests/auto/qdbusabstractadaptor/qmyserver/qmyserver.pro new file mode 100644 index 0000000..f4fe02c --- /dev/null +++ b/tests/auto/qdbusabstractadaptor/qmyserver/qmyserver.pro @@ -0,0 +1,5 @@ +SOURCES = qmyserver.cpp +HEADERS = ../myobject.h +TARGET = qmyserver +QT += dbus +QT -= gui diff --git a/tests/auto/qdbusabstractadaptor/test/test.pro b/tests/auto/qdbusabstractadaptor/test/test.pro new file mode 100644 index 0000000..014a9e8 --- /dev/null +++ b/tests/auto/qdbusabstractadaptor/test/test.pro @@ -0,0 +1,7 @@ +load(qttest_p4) +SOURCES += ../tst_qdbusabstractadaptor.cpp +HEADERS += ../myobject.h +TARGET = ../tst_qdbusabstractadaptor + +QT = core +QT += dbus diff --git a/tests/auto/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp b/tests/auto/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp index a64b3d2..9250350 100644 --- a/tests/auto/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp +++ b/tests/auto/qdbusabstractadaptor/tst_qdbusabstractadaptor.cpp @@ -46,6 +46,11 @@ #include #include "../qdbusmarshall/common.h" +#include "myobject.h" + +static const char serviceName[] = "com.trolltech.autotests.qmyserver"; +static const char objectPath[] = "/com/trolltech/qmyserver"; +static const char *interfaceName = serviceName; const char *slotSpy; QString valueSpy; @@ -73,273 +78,6 @@ namespace QTest { } QT_END_NAMESPACE -class tst_QDBusAbstractAdaptor: public QObject -{ - Q_OBJECT - -private slots: - void initTestCase() { commonInit(); } - void methodCalls_data(); - void methodCalls(); - void methodCallScriptable(); - void signalEmissions_data(); - void signalEmissions(); - void sameSignalDifferentPaths(); - void sameObjectDifferentPaths(); - void scriptableSignalOrNot(); - void overloadedSignalEmission_data(); - void overloadedSignalEmission(); - void readProperties(); - void readPropertiesInvalidInterface(); - void readPropertiesEmptyInterface_data(); - void readPropertiesEmptyInterface(); - void readAllProperties(); - void readAllPropertiesInvalidInterface(); - void readAllPropertiesEmptyInterface_data(); - void readAllPropertiesEmptyInterface(); - void writeProperties(); - - void typeMatching_data(); - void typeMatching(); - - void methodWithMoreThanOneReturnValue(); -}; - -class QDBusSignalSpy: public QObject -{ - Q_OBJECT - -public slots: - void slot(const QDBusMessage &msg) - { - ++count; - interface = msg.interface(); - name = msg.member(); - signature = msg.signature(); - path = msg.path(); - value.clear(); - if (msg.arguments().count()) - value = msg.arguments().at(0); - } - -public: - QDBusSignalSpy() : count(0) { } - - int count; - QString interface; - QString name; - QString signature; - QString path; - QVariant value; -}; - -class Interface1: public QDBusAbstractAdaptor -{ - Q_OBJECT - Q_CLASSINFO("D-Bus Interface", "local.Interface1") -public: - Interface1(QObject *parent) : QDBusAbstractAdaptor(parent) - { } -}; - -class Interface2: public QDBusAbstractAdaptor -{ - Q_OBJECT - Q_CLASSINFO("D-Bus Interface", "local.Interface2") - Q_PROPERTY(QString prop1 READ prop1) - Q_PROPERTY(QString prop2 READ prop2 WRITE setProp2 SCRIPTABLE true) - Q_PROPERTY(QUrl nonDBusProperty READ nonDBusProperty) -public: - Interface2(QObject *parent) : QDBusAbstractAdaptor(parent) - { setAutoRelaySignals(true); } - - QString prop1() const - { return QLatin1String("QString Interface2::prop1() const"); } - - QString prop2() const - { return QLatin1String("QString Interface2::prop2() const"); } - - void setProp2(const QString &value) - { - slotSpy = "void Interface2::setProp2(const QString &)"; - valueSpy = value; - } - - QUrl nonDBusProperty() const - { return QUrl(); } - - void emitSignal(const QString &, const QVariant &) - { emit signal(); } - -public slots: - void method() - { - slotSpy = "void Interface2::method()"; - } - - Q_SCRIPTABLE void scriptableMethod() - { - slotSpy = "void Interface2::scriptableMethod()"; - } - -signals: - void signal(); -}; - -class Interface3: public QDBusAbstractAdaptor -{ - Q_OBJECT - Q_CLASSINFO("D-Bus Interface", "local.Interface3") - Q_PROPERTY(QString prop1 READ prop1) - Q_PROPERTY(QString prop2 READ prop2 WRITE setProp2) - Q_PROPERTY(QString interface3prop READ interface3prop) -public: - Interface3(QObject *parent) : QDBusAbstractAdaptor(parent) - { setAutoRelaySignals(true); } - - QString prop1() const - { return QLatin1String("QString Interface3::prop1() const"); } - - QString prop2() const - { return QLatin1String("QString Interface3::prop2() const"); } - - void setProp2(const QString &value) - { - slotSpy = "void Interface3::setProp2(const QString &)"; - valueSpy = value; - } - - QString interface3prop() const - { return QLatin1String("QString Interface3::interface3prop() const"); } - - void emitSignal(const QString &name, const QVariant &value) - { - if (name == "signalVoid") - emit signalVoid(); - else if (name == "signalInt") - emit signalInt(value.toInt()); - else if (name == "signalString") - emit signalString(value.toString()); - } - -public slots: - void methodVoid() { slotSpy = "void Interface3::methodVoid()"; } - void methodInt(int) { slotSpy = "void Interface3::methodInt(int)"; } - void methodString(QString) { slotSpy = "void Interface3::methodString(QString)"; } - - int methodStringString(const QString &s, QString &out) - { - slotSpy = "int Interface3::methodStringString(const QString &, QString &)"; - out = s; - return 42; - } - -signals: - void signalVoid(); - void signalInt(int); - void signalString(const QString &); -}; - -class Interface4: public QDBusAbstractAdaptor -{ - Q_OBJECT - Q_CLASSINFO("D-Bus Interface", "local.Interface4") - Q_PROPERTY(QString prop1 READ prop1) - Q_PROPERTY(QString prop2 READ prop2 WRITE setProp2) - Q_PROPERTY(QString interface4prop READ interface4prop) -public: - Interface4(QObject *parent) : QDBusAbstractAdaptor(parent) - { setAutoRelaySignals(true); } - - QString prop1() const - { return QLatin1String("QString Interface4::prop1() const"); } - - QString prop2() const - { return QLatin1String("QString Interface4::prop2() const"); } - - QString interface4prop() const - { return QLatin1String("QString Interface4::interface4prop() const"); } - - void setProp2(const QString &value) - { - slotSpy = "void Interface4::setProp2(const QString &)"; - valueSpy = value; - } - - void emitSignal(const QString &, const QVariant &value) - { - switch (value.type()) - { - case QVariant::Invalid: - emit signal(); - break; - case QVariant::Int: - emit signal(value.toInt()); - break; - case QVariant::String: - emit signal(value.toString()); - break; - default: - break; - } - } - -public slots: - void method() { slotSpy = "void Interface4::method()"; } - void method(int) { slotSpy = "void Interface4::method(int)"; } - void method(QString) { slotSpy = "void Interface4::method(QString)"; } - -signals: - void signal(); - void signal(int); - void signal(const QString &); -}; - -class MyObject: public QObject -{ - Q_OBJECT - Q_CLASSINFO("D-Bus Interface", "local.MyObject") -public: - Interface1 *if1; - Interface2 *if2; - Interface3 *if3; - Interface4 *if4; - - MyObject(int n = 4) - : if1(0), if2(0), if3(0), if4(0) - { - switch (n) - { - case 4: - if4 = new Interface4(this); - case 3: - if3 = new Interface3(this); - case 2: - if2 = new Interface2(this); - case 1: - if1 = new Interface1(this); - } - } - - void emitSignal(const QString &name, const QVariant &value) - { - if (name == "scriptableSignalVoid") - emit scriptableSignalVoid(); - else if (name == "scriptableSignalInt") - emit scriptableSignalInt(value.toInt()); - else if (name == "scriptableSignalString") - emit scriptableSignalString(value.toString()); - else if (name == "nonScriptableSignalVoid") - emit nonScriptableSignalVoid(); - } - -signals: - Q_SCRIPTABLE void scriptableSignalVoid(); - Q_SCRIPTABLE void scriptableSignalInt(int); - Q_SCRIPTABLE void scriptableSignalString(QString); - void nonScriptableSignalVoid(); -}; - class TypesInterface: public QDBusAbstractAdaptor { Q_OBJECT @@ -593,6 +331,191 @@ public slots: } }; +void newMyObjectPeer(int nInterfaces = 4) +{ + QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "newMyObject"); + req << nInterfaces; + QDBusMessage reply = QDBusConnection::sessionBus().call(req); +} + +void registerMyObjectPeer(const QString & path, QDBusConnection::RegisterOptions options = QDBusConnection::ExportAdaptors) +{ + QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "registerMyObject"); + req << path; + req << (int)options; + QDBusMessage reply = QDBusConnection::sessionBus().call(req); +} + +void emitSignalPeer(const QString &interface, const QString &name, const QVariant ¶meter) +{ + if (parameter.isValid()) + { + QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "emitSignal"); + req << interface; + req << name; + req << QVariant::fromValue(QDBusVariant(parameter)); + QDBusConnection::sessionBus().send(req); + } + else + { + QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "emitSignal2"); + req << interface; + req << name; + QDBusConnection::sessionBus().send(req); + } + + QTest::qWait(1000); +} + +const char* slotSpyPeer() +{ + QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "slotSpyServer"); + QDBusMessage reply = QDBusConnection::sessionBus().call(req); + return reply.arguments().at(0).toString().toLatin1().data(); +} + +QString valueSpyPeer() +{ + QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "valueSpyServer"); + QDBusMessage reply = QDBusConnection::sessionBus().call(req); + return reply.arguments().at(0).toString(); +} + +void clearValueSpyPeer() +{ + QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "clearValueSpy"); + QDBusMessage reply = QDBusConnection::sessionBus().call(req); +} + +class tst_QDBusAbstractAdaptor: public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + void cleanupTestCase(); + + void methodCalls_data(); + void methodCalls(); + void methodCallScriptable(); + void signalEmissions_data(); + void signalEmissions(); + void sameSignalDifferentPaths(); + void sameObjectDifferentPaths(); + void scriptableSignalOrNot(); + void overloadedSignalEmission_data(); + void overloadedSignalEmission(); + void readProperties(); + void readPropertiesInvalidInterface(); + void readPropertiesEmptyInterface_data(); + void readPropertiesEmptyInterface(); + void readAllProperties(); + void readAllPropertiesInvalidInterface(); + void readAllPropertiesEmptyInterface_data(); + void readAllPropertiesEmptyInterface(); + void writeProperties(); + + void methodCallsPeer_data(); + void methodCallsPeer(); + void methodCallScriptablePeer(); + void signalEmissionsPeer_data(); + void signalEmissionsPeer(); + void sameSignalDifferentPathsPeer(); + void sameObjectDifferentPathsPeer(); + void scriptableSignalOrNotPeer(); + void overloadedSignalEmissionPeer_data(); + void overloadedSignalEmissionPeer(); + void readPropertiesPeer(); + void readPropertiesInvalidInterfacePeer(); + void readPropertiesEmptyInterfacePeer_data(); + void readPropertiesEmptyInterfacePeer(); + void readAllPropertiesPeer(); + void readAllPropertiesInvalidInterfacePeer(); + void readAllPropertiesEmptyInterfacePeer_data(); + void readAllPropertiesEmptyInterfacePeer(); + void writePropertiesPeer(); + + void typeMatching_data(); + void typeMatching(); + + void methodWithMoreThanOneReturnValue(); + void methodWithMoreThanOneReturnValuePeer(); +private: + QProcess proc; +}; + +class WaitForQMyServer: public QObject +{ + Q_OBJECT +public: + WaitForQMyServer(); + bool ok(); +public Q_SLOTS: + void ownerChange(const QString &name) + { + if (name == serviceName) + loop.quit(); + } + +private: + QEventLoop loop; +}; + +WaitForQMyServer::WaitForQMyServer() +{ + QDBusConnection con = QDBusConnection::sessionBus(); + if (!ok()) { + connect(con.interface(), SIGNAL(serviceOwnerChanged(QString,QString,QString)), + SLOT(ownerChange(QString))); + QTimer::singleShot(2000, &loop, SLOT(quit())); + loop.exec(); + } +} + +bool WaitForQMyServer::ok() +{ + return QDBusConnection::sessionBus().isConnected() && + QDBusConnection::sessionBus().interface()->isServiceRegistered(serviceName); +} + +void tst_QDBusAbstractAdaptor::initTestCase() +{ + commonInit(); + + // start peer server + #ifdef Q_OS_WIN + proc.start("qmyserver"); + #else + proc.start("./qmyserver/qmyserver"); + #endif + QVERIFY(proc.waitForStarted()); + + WaitForQMyServer w; + QVERIFY(w.ok()); + //QTest::qWait(2000); + + // get peer server address + QDBusMessage req = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "address"); + QDBusMessage rpl = QDBusConnection::sessionBus().call(req); + QVERIFY(rpl.type() == QDBusMessage::ReplyMessage); + QString address = rpl.arguments().at(0).toString(); + + // connect to peer server + QDBusConnection peercon = QDBusConnection::connectToPeer(address, "peer"); + QVERIFY(peercon.isConnected()); + + QDBusMessage req2 = QDBusMessage::createMethodCall(serviceName, objectPath, interfaceName, "isConnected"); + QDBusMessage rpl2 = QDBusConnection::sessionBus().call(req2); + QVERIFY(rpl2.type() == QDBusMessage::ReplyMessage); + QVERIFY(rpl2.arguments().at(0).toBool()); +} + +void tst_QDBusAbstractAdaptor::cleanupTestCase() +{ + proc.close(); + proc.kill(); +} + void tst_QDBusAbstractAdaptor::methodCalls_data() { QTest::addColumn("nInterfaces"); @@ -1151,71 +1074,577 @@ void tst_QDBusAbstractAdaptor::writeProperties() } } -#if 0 -void tst_QDBusAbstractAdaptor::adaptorIntrospection_data() +void tst_QDBusAbstractAdaptor::methodCallsPeer_data() { methodCalls_data(); } -void tst_QDBusAbstractAdaptor::adaptorIntrospection() +void tst_QDBusAbstractAdaptor::methodCallsPeer() { - QDBusConnection con = QDBus::sessionBus(); + QDBusConnection con("peer"); QVERIFY(con.isConnected()); - QObject obj; - con.registerObject("/", &obj); - - QFETCH(int, nInterfaces); - switch (nInterfaces) { - case 4: - new Interface4(&obj); - case 3: - new Interface3(&obj); - case 2: - new Interface2(&obj); - case 1: - new Interface1(&obj); + // must fail: no object + QDBusInterface if1(QString(), "/", "local.Interface1", con); + QCOMPARE(if1.call(QDBus::BlockWithGui, "method").type(), QDBusMessage::ErrorMessage); } - QDBusObject dobj = con.findObject(con.baseService(), "/"); - QVERIFY(dobj.isValid()); + QFETCH(int, nInterfaces); + newMyObjectPeer(nInterfaces); + registerMyObjectPeer("/"); - QString xml = dobj.introspect(); - QVERIFY(!xml.isEmpty()); + QDBusInterface if1(QString(), "/", "local.Interface1", con); + QDBusInterface if2(QString(), "/", "local.Interface2", con); + QDBusInterface if3(QString(), "/", "local.Interface3", con); + QDBusInterface if4(QString(), "/", "local.Interface4", con); - QStringList interfaces = dobj.interfaces(); - QCOMPARE(interfaces.count(), nInterfaces + 2); - switch (nInterfaces) - { - case 4: { - QVERIFY(interfaces.contains("local.Interface4")); - QDBusInterface iface(dobj, "local.Interface4"); - QCOMPARE(iface.methodData(), Interface4::methodData); - QCOMPARE(iface.signalData(), Interface4::signalData); - QCOMPARE(iface.propertyData(), Interface4::propertyData); - } - case 3: { - QVERIFY(interfaces.contains("local.Interface3")); - QDBusInterface iface(dobj, "local.Interface3"); - QCOMPARE(iface.methodData(), Interface3::methodData); - QCOMPARE(iface.signalData(), Interface3::signalData); - QCOMPARE(iface.propertyData(), Interface3::propertyData); - } - case 2: { - QVERIFY(interfaces.contains("local.Interface2")); - QDBusInterface iface(dobj, "local.Interface2"); - QCOMPARE(iface.methodData(), Interface2::methodData); - QCOMPARE(iface.signalData(), Interface2::signalData); - QCOMPARE(iface.propertyData(), Interface2::propertyData); - } - case 1: { - QVERIFY(interfaces.contains("local.Interface1")); - QDBusInterface iface(dobj, "local.Interface1"); - QCOMPARE(iface.methodData(), Interface1::methodData); - QCOMPARE(iface.signalData(), Interface1::signalData); - QCOMPARE(iface.propertyData(), Interface1::propertyData); - } + // must fail: no such method + QCOMPARE(if1.call(QDBus::BlockWithGui, "method").type(), QDBusMessage::ErrorMessage); + if (!nInterfaces--) + return; + if (!nInterfaces--) + return; + + // simple call: one such method exists + QCOMPARE(if2.call(QDBus::BlockWithGui, "method").type(), QDBusMessage::ReplyMessage); + QCOMPARE(slotSpyPeer(), "void Interface2::method()"); + if (!nInterfaces--) + return; + + // multiple methods in multiple interfaces, no name overlap + QCOMPARE(if1.call(QDBus::BlockWithGui, "methodVoid").type(), QDBusMessage::ErrorMessage); + QCOMPARE(if1.call(QDBus::BlockWithGui, "methodInt").type(), QDBusMessage::ErrorMessage); + QCOMPARE(if1.call(QDBus::BlockWithGui, "methodString").type(), QDBusMessage::ErrorMessage); + QCOMPARE(if2.call(QDBus::BlockWithGui, "methodVoid").type(), QDBusMessage::ErrorMessage); + QCOMPARE(if2.call(QDBus::BlockWithGui, "methodInt").type(), QDBusMessage::ErrorMessage); + QCOMPARE(if2.call(QDBus::BlockWithGui, "methodString").type(), QDBusMessage::ErrorMessage); + + QCOMPARE(if3.call(QDBus::BlockWithGui, "methodVoid").type(), QDBusMessage::ReplyMessage); + QCOMPARE(slotSpyPeer(), "void Interface3::methodVoid()"); + QCOMPARE(if3.call(QDBus::BlockWithGui, "methodInt", 42).type(), QDBusMessage::ReplyMessage); + QCOMPARE(slotSpyPeer(), "void Interface3::methodInt(int)"); + QCOMPARE(if3.call(QDBus::BlockWithGui, "methodString", QString("")).type(), QDBusMessage::ReplyMessage); + QCOMPARE(slotSpyPeer(), "void Interface3::methodString(QString)"); + + if (!nInterfaces--) + return; + + // method overloading: different interfaces + QCOMPARE(if4.call(QDBus::BlockWithGui, "method").type(), QDBusMessage::ReplyMessage); + QCOMPARE(slotSpyPeer(), "void Interface4::method()"); + + // method overloading: different parameters + QCOMPARE(if4.call(QDBus::BlockWithGui, "method.i", 42).type(), QDBusMessage::ReplyMessage); + QCOMPARE(slotSpyPeer(), "void Interface4::method(int)"); + QCOMPARE(if4.call(QDBus::BlockWithGui, "method.s", QString()).type(), QDBusMessage::ReplyMessage); + QCOMPARE(slotSpyPeer(), "void Interface4::method(QString)"); +} + +void tst_QDBusAbstractAdaptor::methodCallScriptablePeer() +{ + QDBusConnection con("peer"); + QVERIFY(con.isConnected()); + + newMyObjectPeer(2); + registerMyObjectPeer("/"); + + QDBusInterface if2(QString(), "/", "local.Interface2", con); + + QCOMPARE(if2.call(QDBus::BlockWithGui,"scriptableMethod").type(), QDBusMessage::ReplyMessage); + QCOMPARE(slotSpyPeer(), "void Interface2::scriptableMethod()"); +} + +void tst_QDBusAbstractAdaptor::signalEmissionsPeer_data() +{ + signalEmissions_data(); +} + +void tst_QDBusAbstractAdaptor::signalEmissionsPeer() +{ + QFETCH(QString, interface); + QFETCH(QString, name); + QFETCH(QVariant, parameter); + + QDBusConnection con("peer"); + QVERIFY(con.isConnected()); + + newMyObjectPeer(3); + registerMyObjectPeer("/", QDBusConnection::ExportAdaptors + | QDBusConnection::ExportScriptableSignals); + + // connect all signals and emit only one + { + QDBusSignalSpy spy; + con.connect(QString(), "/", "local.Interface2", "signal", + &spy, SLOT(slot(QDBusMessage))); + con.connect(QString(), "/", "local.Interface3", "signalVoid", + &spy, SLOT(slot(QDBusMessage))); + con.connect(QString(), "/", "local.Interface3", "signalInt", + &spy, SLOT(slot(QDBusMessage))); + con.connect(QString(), "/", "local.Interface3", "signalString", + &spy, SLOT(slot(QDBusMessage))); + con.connect(QString(), "/", "local.MyObject", "scriptableSignalVoid", + &spy, SLOT(slot(QDBusMessage))); + con.connect(QString(), "/", "local.MyObject", "scriptableSignalInt", + &spy, SLOT(slot(QDBusMessage))); + con.connect(QString(), "/", "local.MyObject", "scriptableSignalString", + &spy, SLOT(slot(QDBusMessage))); + + emitSignalPeer(interface, name, parameter); + + QCOMPARE(spy.count, 1); + QCOMPARE(spy.interface, interface); + QCOMPARE(spy.name, name); + QTEST(spy.signature, "signature"); + QCOMPARE(spy.value, parameter); + } + + // connect one signal and emit them all + { + QDBusSignalSpy spy; + con.connect(QString(), "/", interface, name, &spy, SLOT(slot(QDBusMessage))); + emitSignalPeer("local.Interface2", "signal", QVariant()); + emitSignalPeer("local.Interface3", "signalVoid", QVariant()); + emitSignalPeer("local.Interface3", "signalInt", QVariant(1)); + emitSignalPeer("local.Interface3", "signalString", QVariant("foo")); + emitSignalPeer("local.MyObject", "scriptableSignalVoid", QVariant()); + emitSignalPeer("local.MyObject", "scriptableSignalInt", QVariant(1)); + emitSignalPeer("local.MyObject", "scriptableSignalString", QVariant("foo")); + + QCOMPARE(spy.count, 1); + QCOMPARE(spy.interface, interface); + QCOMPARE(spy.name, name); + QTEST(spy.signature, "signature"); + QCOMPARE(spy.value, parameter); + } +} + +void tst_QDBusAbstractAdaptor::sameSignalDifferentPathsPeer() +{ + QDBusConnection con("peer"); + QVERIFY(con.isConnected()); + + newMyObjectPeer(2); + + registerMyObjectPeer("/p1"); + registerMyObjectPeer("/p2"); + + QDBusSignalSpy spy; + con.connect(QString(), "/p1", "local.Interface2", "signal", &spy, SLOT(slot(QDBusMessage))); + emitSignalPeer("local.Interface2", QString(), QVariant()); + QTest::qWait(200); + + QCOMPARE(spy.count, 1); + QCOMPARE(spy.interface, QString("local.Interface2")); + QCOMPARE(spy.name, QString("signal")); + QVERIFY(spy.signature.isEmpty()); + + // now connect the other one + spy.count = 0; + con.connect(QString(), "/p2", "local.Interface2", "signal", &spy, SLOT(slot(QDBusMessage))); + emitSignalPeer("local.Interface2", QString(), QVariant()); + QTest::qWait(200); + + QCOMPARE(spy.count, 2); +} + +void tst_QDBusAbstractAdaptor::sameObjectDifferentPathsPeer() +{ + QDBusConnection con("peer"); + QVERIFY(con.isConnected()); + + newMyObjectPeer(2); + + registerMyObjectPeer("/p1"); + registerMyObjectPeer("/p2", 0); // don't export anything + + QDBusSignalSpy spy; + con.connect(QString(), "/p1", "local.Interface2", "signal", &spy, SLOT(slot(QDBusMessage))); + con.connect(QString(), "/p2", "local.Interface2", "signal", &spy, SLOT(slot(QDBusMessage))); + emitSignalPeer("local.Interface2", QString(), QVariant()); + QTest::qWait(200); + + QCOMPARE(spy.count, 1); + QCOMPARE(spy.interface, QString("local.Interface2")); + QCOMPARE(spy.name, QString("signal")); + QVERIFY(spy.signature.isEmpty()); +} + +void tst_QDBusAbstractAdaptor::scriptableSignalOrNotPeer() +{ + QDBusConnection con("peer");; + QVERIFY(con.isConnected()); + + { + newMyObjectPeer(0); + + registerMyObjectPeer("/p1", QDBusConnection::ExportScriptableSignals); + registerMyObjectPeer("/p2", 0); // don't export anything + + QDBusSignalSpy spy; + con.connect(QString(), "/p1", "local.MyObject", "scriptableSignalVoid", &spy, SLOT(slot(QDBusMessage))); + con.connect(QString(), "/p2", "local.MyObject", "scriptableSignalVoid", &spy, SLOT(slot(QDBusMessage))); + con.connect(QString(), "/p1", "local.MyObject", "nonScriptableSignalVoid", &spy, SLOT(slot(QDBusMessage))); + con.connect(QString(), "/p2", "local.MyObject", "nonScriptableSignalVoid", &spy, SLOT(slot(QDBusMessage))); + emitSignalPeer("local.MyObject", "scriptableSignalVoid", QVariant()); + emitSignalPeer("local.MyObject", "nonScriptableSignalVoid", QVariant()); + QTest::qWait(200); + + QCOMPARE(spy.count, 1); // only /p1 must have emitted + QCOMPARE(spy.interface, QString("local.MyObject")); + QCOMPARE(spy.name, QString("scriptableSignalVoid")); + QCOMPARE(spy.path, QString("/p1")); + QVERIFY(spy.signature.isEmpty()); + } + + { + newMyObjectPeer(0); + + registerMyObjectPeer("/p1", QDBusConnection::ExportScriptableSignals); + registerMyObjectPeer("/p2", QDBusConnection::ExportScriptableSignals + | QDBusConnection::ExportNonScriptableSignals); + + QDBusSignalSpy spy; + con.connect(QString(), "/p1", "local.MyObject", "nonScriptableSignalVoid", &spy, SLOT(slot(QDBusMessage))); + con.connect(QString(), "/p2", "local.MyObject", "nonScriptableSignalVoid", &spy, SLOT(slot(QDBusMessage))); + emitSignalPeer("local.MyObject", "nonScriptableSignalVoid", QVariant()); + QTest::qWait(200); + + QCOMPARE(spy.count, 1); // only /p2 must have emitted now + QCOMPARE(spy.interface, QString("local.MyObject")); + QCOMPARE(spy.name, QString("nonScriptableSignalVoid")); + QCOMPARE(spy.path, QString("/p2")); + QVERIFY(spy.signature.isEmpty()); + } + + { + QDBusSignalSpy spy; + con.connect(QString(), "/p1", "local.MyObject", "destroyed", &spy, SLOT(slot(QDBusMessage))); + con.connect(QString(), "/p2", "local.MyObject", "destroyed", &spy, SLOT(slot(QDBusMessage))); + + { + newMyObjectPeer(0); + + registerMyObjectPeer("/p1", QDBusConnection::ExportScriptableSignals); + registerMyObjectPeer("/p2", QDBusConnection::ExportScriptableSignals + | QDBusConnection::ExportNonScriptableSignals); + } // <--- QObject emits the destroyed(QObject*) signal at this point + + QTest::qWait(200); + + QCOMPARE(spy.count, 0); + } +} + +void tst_QDBusAbstractAdaptor::overloadedSignalEmissionPeer_data() +{ + overloadedSignalEmission_data(); +} + +void tst_QDBusAbstractAdaptor::overloadedSignalEmissionPeer() +{ + QDBusConnection con("peer"); + QVERIFY(con.isConnected()); + + newMyObjectPeer(); + registerMyObjectPeer("/"); + + QString interface = "local.Interface4"; + QString name = "signal"; + QFETCH(QVariant, parameter); + //QDBusInterface *if4 = new QDBusInterface(QString(), "/", interface, con); + + // connect all signals and emit only one + { + QDBusSignalSpy spy; + con.connect(QString(), "/", "local.Interface4", "signal", "", + &spy, SLOT(slot(QDBusMessage))); + con.connect(QString(), "/", "local.Interface4", "signal", "i", + &spy, SLOT(slot(QDBusMessage))); + con.connect(QString(), "/", "local.Interface4", "signal", "s", + &spy, SLOT(slot(QDBusMessage))); + + emitSignalPeer(interface, name, parameter); + + QCOMPARE(spy.count, 1); + QCOMPARE(spy.interface, interface); + QCOMPARE(spy.name, name); + QTEST(spy.signature, "signature"); + QCOMPARE(spy.value, parameter); + } + + QFETCH(QString, signature); + // connect one signal and emit them all + { + QDBusSignalSpy spy; + con.connect(QString(), "/", interface, name, signature, &spy, SLOT(slot(QDBusMessage))); + emitSignalPeer("local.Interface4", "signal", QVariant()); + emitSignalPeer("local.Interface4", "signal", QVariant(1)); + emitSignalPeer("local.Interface4", "signal", QVariant("foo")); + + QCOMPARE(spy.count, 1); + QCOMPARE(spy.interface, interface); + QCOMPARE(spy.name, name); + QTEST(spy.signature, "signature"); + QCOMPARE(spy.value, parameter); + } +} + +void tst_QDBusAbstractAdaptor::readPropertiesPeer() +{ + QDBusConnection con("peer"); + QVERIFY(con.isConnected()); + + newMyObjectPeer(); + registerMyObjectPeer("/"); + + QDBusInterface properties(QString(), "/", "org.freedesktop.DBus.Properties", con); + for (int i = 2; i <= 4; ++i) { + QString name = QString("Interface%1").arg(i); + + for (int j = 1; j <= 2; ++j) { + QString propname = QString("prop%1").arg(j); + QDBusReply reply = + properties.call(QDBus::BlockWithGui, "Get", "local." + name, propname); + QVariant value = reply; + + QCOMPARE(value.userType(), int(QVariant::String)); + QCOMPARE(value.toString(), QString("QString %1::%2() const").arg(name, propname)); + } + } +} + +void tst_QDBusAbstractAdaptor::readPropertiesInvalidInterfacePeer() +{ + QDBusConnection con("peer"); + QVERIFY(con.isConnected()); + + newMyObjectPeer(); + registerMyObjectPeer("/"); + + QDBusInterface properties(QString(), "/", "org.freedesktop.DBus.Properties", con); + + // test an invalid interface: + QDBusReply reply = properties.call(QDBus::BlockWithGui, "Get", "local.DoesntExist", "prop1"); + QVERIFY(!reply.isValid()); +} + +void tst_QDBusAbstractAdaptor::readPropertiesEmptyInterfacePeer_data() +{ + readPropertiesEmptyInterface_data(); +} + +void tst_QDBusAbstractAdaptor::readPropertiesEmptyInterfacePeer() +{ + QDBusConnection con("peer"); + QVERIFY(con.isConnected()); + + newMyObjectPeer(); + registerMyObjectPeer("/"); + + QDBusInterface properties(QString(), "/", "org.freedesktop.DBus.Properties", con); + + QFETCH(QVariantMap, expectedProperties); + QFETCH(bool, existing); + + QVariantMap::ConstIterator it = expectedProperties.constBegin(); + for ( ; it != expectedProperties.constEnd(); ++it) { + QDBusReply reply = properties.call(QDBus::BlockWithGui, "Get", "", it.key()); + + if (existing) { + QVERIFY2(reply.isValid(), qPrintable(it.key())); + } else { + QVERIFY2(!reply.isValid(), qPrintable(it.key())); + continue; + } + + QCOMPARE(int(reply.value().type()), int(QVariant::String)); + if (it.value().isValid()) + QCOMPARE(reply.value().toString(), it.value().toString()); + } +} + +void tst_QDBusAbstractAdaptor::readAllPropertiesPeer() +{ + QDBusConnection con("peer"); + QVERIFY(con.isConnected()); + + newMyObjectPeer(); + registerMyObjectPeer("/"); + + QDBusInterface properties(QString(), "/", "org.freedesktop.DBus.Properties", con); + for (int i = 2; i <= 4; ++i) { + QString name = QString("Interface%1").arg(i); + QDBusReply reply = + properties.call(QDBus::BlockWithGui, "GetAll", "local." + name); + + for (int j = 1; j <= 2; ++j) { + QString propname = QString("prop%1").arg(j); + QVERIFY2(reply.value().contains(propname), + qPrintable(propname + " on " + name)); + QVariant value = reply.value().value(propname); + + QCOMPARE(value.userType(), int(QVariant::String)); + QCOMPARE(value.toString(), QString("QString %1::%2() const").arg(name, propname)); + } + } +} + +void tst_QDBusAbstractAdaptor::readAllPropertiesInvalidInterfacePeer() +{ + QDBusConnection con("peer"); + QVERIFY(con.isConnected()); + + newMyObjectPeer(); + registerMyObjectPeer("/"); + + QDBusInterface properties(QString(), "/", "org.freedesktop.DBus.Properties", con); + + // test an invalid interface: + QDBusReply reply = properties.call(QDBus::BlockWithGui, "GetAll", "local.DoesntExist"); + QVERIFY(!reply.isValid()); +} + +void tst_QDBusAbstractAdaptor::readAllPropertiesEmptyInterfacePeer_data() +{ + readAllPropertiesEmptyInterface_data(); +} + +void tst_QDBusAbstractAdaptor::readAllPropertiesEmptyInterfacePeer() +{ + QDBusConnection con("peer"); + QVERIFY(con.isConnected()); + + newMyObjectPeer(); + registerMyObjectPeer("/"); + + QDBusInterface properties(QString(), "/", "org.freedesktop.DBus.Properties", con); + + QDBusReply reply = properties.call(QDBus::BlockWithGui, "GetAll", ""); + QVERIFY(reply.isValid()); + + QVariantMap allprops = reply; + + QFETCH(QVariantMap, expectedProperties); + QFETCH(bool, existing); + + QVariantMap::ConstIterator it = expectedProperties.constBegin(); + if (existing) { + for ( ; it != expectedProperties.constEnd(); ++it) { + QVERIFY2(allprops.contains(it.key()), qPrintable(it.key())); + + QVariant propvalue = allprops.value(it.key()); + QVERIFY2(!propvalue.isNull(), qPrintable(it.key())); + QVERIFY2(propvalue.isValid(), qPrintable(it.key())); + + QString stringvalue = propvalue.toString(); + QVERIFY2(!stringvalue.isEmpty(), qPrintable(it.key())); + + if (it.value().isValid()) + QCOMPARE(stringvalue, it.value().toString()); + + // remove this property from the map + allprops.remove(it.key()); + } + + QVERIFY2(allprops.isEmpty(), + qPrintable(QStringList(allprops.keys()).join(" "))); + } else { + for ( ; it != expectedProperties.constEnd(); ++it) + QVERIFY2(!allprops.contains(it.key()), qPrintable(it.key())); + } +} + +void tst_QDBusAbstractAdaptor::writePropertiesPeer() +{ + QDBusConnection con("peer"); + QVERIFY(con.isConnected()); + + newMyObjectPeer(); + registerMyObjectPeer("/"); + + QDBusInterface properties(QString(), "/", "org.freedesktop.DBus.Properties", con); + for (int i = 2; i <= 4; ++i) { + QString name = QString("Interface%1").arg(i); + + clearValueSpyPeer(); + properties.call(QDBus::BlockWithGui, "Set", "local." + name, QString("prop1"), + qVariantFromValue(QDBusVariant(name))); + QVERIFY(valueSpyPeer().isEmpty()); // call mustn't have succeeded + + properties.call(QDBus::BlockWithGui, "Set", "local." + name, QString("prop2"), + qVariantFromValue(QDBusVariant(name))); + QCOMPARE(valueSpyPeer(), name); + QCOMPARE(QString(slotSpyPeer()), QString("void %1::setProp2(const QString &)").arg(name)); + } +} + +#if 0 +void tst_QDBusAbstractAdaptor::adaptorIntrospection_data() +{ + methodCalls_data(); +} + +void tst_QDBusAbstractAdaptor::adaptorIntrospection() +{ + QDBusConnection con = QDBus::sessionBus(); + QVERIFY(con.isConnected()); + + QObject obj; + con.registerObject("/", &obj); + + QFETCH(int, nInterfaces); + switch (nInterfaces) + { + case 4: + new Interface4(&obj); + case 3: + new Interface3(&obj); + case 2: + new Interface2(&obj); + case 1: + new Interface1(&obj); + } + + QDBusObject dobj = con.findObject(con.baseService(), "/"); + QVERIFY(dobj.isValid()); + + QString xml = dobj.introspect(); + QVERIFY(!xml.isEmpty()); + + QStringList interfaces = dobj.interfaces(); + QCOMPARE(interfaces.count(), nInterfaces + 2); + switch (nInterfaces) + { + case 4: { + QVERIFY(interfaces.contains("local.Interface4")); + QDBusInterface iface(dobj, "local.Interface4"); + QCOMPARE(iface.methodData(), Interface4::methodData); + QCOMPARE(iface.signalData(), Interface4::signalData); + QCOMPARE(iface.propertyData(), Interface4::propertyData); + } + case 3: { + QVERIFY(interfaces.contains("local.Interface3")); + QDBusInterface iface(dobj, "local.Interface3"); + QCOMPARE(iface.methodData(), Interface3::methodData); + QCOMPARE(iface.signalData(), Interface3::signalData); + QCOMPARE(iface.propertyData(), Interface3::propertyData); + } + case 2: { + QVERIFY(interfaces.contains("local.Interface2")); + QDBusInterface iface(dobj, "local.Interface2"); + QCOMPARE(iface.methodData(), Interface2::methodData); + QCOMPARE(iface.signalData(), Interface2::signalData); + QCOMPARE(iface.propertyData(), Interface2::propertyData); + } + case 1: { + QVERIFY(interfaces.contains("local.Interface1")); + QDBusInterface iface(dobj, "local.Interface1"); + QCOMPARE(iface.methodData(), Interface1::methodData); + QCOMPARE(iface.signalData(), Interface1::signalData); + QCOMPARE(iface.propertyData(), Interface1::propertyData); + } } } @@ -1438,6 +1867,28 @@ void tst_QDBusAbstractAdaptor::methodWithMoreThanOneReturnValue() QCOMPARE(qdbus_cast(reply.arguments().at(1)), testString); } +void tst_QDBusAbstractAdaptor::methodWithMoreThanOneReturnValuePeer() +{ + QDBusConnection con("peer"); + QVERIFY(con.isConnected()); + + newMyObjectPeer(); + registerMyObjectPeer("/"); + + QString testString = "This is a test string."; + + QDBusInterface remote(QString(), "/", "local.Interface3", con); + QDBusMessage reply = remote.call(QDBus::BlockWithGui, "methodStringString", testString); + QVERIFY(reply.arguments().count() == 2); + + QDBusReply intreply = reply; + QVERIFY(intreply.isValid()); + QCOMPARE(intreply.value(), 42); + + QCOMPARE(reply.arguments().at(1).userType(), int(QVariant::String)); + QCOMPARE(qdbus_cast(reply.arguments().at(1)), testString); +} + QTEST_MAIN(tst_QDBusAbstractAdaptor) #include "tst_qdbusabstractadaptor.moc" -- cgit v0.12 From 708e090aef81c59904c483a2ea46b275ef21c7e4 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Tue, 19 Apr 2011 12:01:17 +1000 Subject: Fix excessive scrolling in TextInput with mid string pre-edit text. Don't emit text or cursor position changed signals until all the state changes from the input method event are made. Otherwise properties like horizontal scroll are updated based on invalid intermediate data. Change-Id: If543dbe58dc571aeda495152d99be95645eea140 Task-number: QTBUG-18789 Reviewed-by: Martin Jones --- src/gui/widgets/qlinecontrol.cpp | 2 +- .../qdeclarativetextinput/tst_qdeclarativetextinput.cpp | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp index 5a281ad..d03e5de 100644 --- a/src/gui/widgets/qlinecontrol.cpp +++ b/src/gui/widgets/qlinecontrol.cpp @@ -435,7 +435,7 @@ void QLineControl::processInputMethodEvent(QInputMethodEvent *event) removeSelectedText(); } if (!event->commitString().isEmpty()) { - insert(event->commitString()); + internalInsert(event->commitString()); cursorPositionChanged = true; } diff --git a/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp b/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp index ef32ee3..943b1fa 100644 --- a/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp +++ b/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp @@ -2285,6 +2285,20 @@ void tst_qdeclarativetextinput::preeditAutoScroll() ic.sendPreeditText(preeditText.mid(0, 3), 1); QCOMPARE(input.positionAt(0), 0); QCOMPARE(input.positionAt(input.width()), 5); + + ic.sendEvent(QInputMethodEvent()); + input.setAutoScroll(true); + // Test committing pre-edit text at the start of the string. QTBUG-18789 + input.setCursorPosition(0); + ic.sendPreeditText(input.text(), 5); + QCOMPARE(input.positionAt(0), 0); + + QInputMethodEvent event; + event.setCommitString(input.text()); + ic.sendEvent(event); + + QCOMPARE(input.positionAt(0), 0); + QCOMPARE(input.positionAt(input.width()), 5); } void tst_qdeclarativetextinput::preeditMicroFocus() -- cgit v0.12 From 47819dc7257c60e0feb1d02177622593ec0c2d15 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Tue, 22 Mar 2011 10:57:59 +0100 Subject: Long live QRawFont! The QGlyphs API was initially attempted with a bastardization of QFont which was meant to encapsulate a single, physical font instance (a QFontEngine) where a set of glyph indexes would make sense. This is not how QFont was intended to be used, and it caused several issues. At the same time, the requirement for loading a font from ttf/otf data and be able to access it and use it without polluting the rest of the process with the font arose. To support these two APIs we introduce QRawFont, which is an abstraction on top of a single physical font. Done-with: Jiang Jiang --- src/corelib/global/qglobal.h | 6 + src/gui/painting/qpaintbuffer.cpp | 23 +- src/gui/painting/qpainter.cpp | 54 +- src/gui/painting/qpainter.h | 2 + src/gui/painting/qpainter_p.h | 10 +- src/gui/text/qfont.cpp | 26 +- src/gui/text/qfont_win.cpp | 17 +- src/gui/text/qfontdatabase.cpp | 27 +- src/gui/text/qfontdatabase_mac.cpp | 7 +- src/gui/text/qfontdatabase_s60.cpp | 2 +- src/gui/text/qfontdatabase_win.cpp | 90 +-- src/gui/text/qfontengine.cpp | 18 - src/gui/text/qfontengine_coretext.mm | 316 +++++++---- src/gui/text/qfontengine_coretext_p.h | 27 +- src/gui/text/qfontengine_ft.cpp | 162 +++++- src/gui/text/qfontengine_ft_p.h | 15 +- src/gui/text/qfontengine_mac.mm | 21 - src/gui/text/qfontengine_mac_p.h | 2 - src/gui/text/qfontengine_p.h | 5 +- src/gui/text/qfontengine_x11_p.h | 1 + src/gui/text/qfontenginedirectwrite.cpp | 54 +- src/gui/text/qfontenginedirectwrite_p.h | 11 +- src/gui/text/qglyphs.cpp | 97 +++- src/gui/text/qglyphs.h | 19 +- src/gui/text/qglyphs_p.h | 25 +- src/gui/text/qrawfont.cpp | 612 ++++++++++++++++++++ src/gui/text/qrawfont.h | 140 +++++ src/gui/text/qrawfont_ft.cpp | 189 +++++++ src/gui/text/qrawfont_mac.cpp | 105 ++++ src/gui/text/qrawfont_p.h | 132 +++++ src/gui/text/qrawfont_win.cpp | 750 +++++++++++++++++++++++++ src/gui/text/qtextlayout.cpp | 58 +- src/gui/text/qtextlayout.h | 5 + src/gui/text/qtextobject.cpp | 2 + src/gui/text/qtextobject.h | 2 + src/gui/text/text.pri | 22 +- tests/auto/gui.pro | 1 + tests/auto/qglyphs/tst_qglyphs.cpp | 17 +- tests/auto/qrawfont/qrawfont.pro | 13 + tests/auto/qrawfont/testfont.ttf | Bin 0 -> 63212 bytes tests/auto/qrawfont/testfont_bold_italic.ttf | Bin 0 -> 49760 bytes tests/auto/qrawfont/tst_qrawfont.cpp | 812 +++++++++++++++++++++++++++ 42 files changed, 3509 insertions(+), 388 deletions(-) create mode 100644 src/gui/text/qrawfont.cpp create mode 100644 src/gui/text/qrawfont.h create mode 100644 src/gui/text/qrawfont_ft.cpp create mode 100644 src/gui/text/qrawfont_mac.cpp create mode 100644 src/gui/text/qrawfont_p.h create mode 100644 src/gui/text/qrawfont_win.cpp create mode 100644 tests/auto/qrawfont/qrawfont.pro create mode 100644 tests/auto/qrawfont/testfont.ttf create mode 100644 tests/auto/qrawfont/testfont_bold_italic.ttf create mode 100644 tests/auto/qrawfont/tst_qrawfont.cpp diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 7c5c354..d8ffd6d 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -2743,6 +2743,12 @@ QT_LICENSED_MODULE(DBus) # endif #endif +#if !(defined(Q_WS_WIN) && !defined(Q_WS_WINCE)) \ + && !(defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA)) \ + && !(defined(Q_WS_X11) && !defined(QT_NO_FREETYPE)) +# define QT_NO_RAWFONT +#endif + QT_END_NAMESPACE QT_END_HEADER diff --git a/src/gui/painting/qpaintbuffer.cpp b/src/gui/painting/qpaintbuffer.cpp index dd4b3db..7870def 100644 --- a/src/gui/painting/qpaintbuffer.cpp +++ b/src/gui/painting/qpaintbuffer.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include @@ -1754,26 +1755,38 @@ void QPainterReplayer::process(const QPaintBufferCommand &cmd) painter->setClipRegion(region, Qt::ClipOperation(cmd.extra)); break; } +#if !defined(QT_NO_RAWFONT) case QPaintBufferPrivate::Cmd_DrawStaticText: { QVariantList variants(d->variants.at(cmd.offset).value()); QFont font = variants.at(0).value(); - QVector glyphs; + QVector glyphIndexes; QVector positions; for (int i=0; i<(variants.size() - 1) / 2; ++i) { - glyphs.append(variants.at(i*2 + 1).toUInt()); + glyphIndexes.append(variants.at(i*2 + 1).toUInt()); positions.append(variants.at(i*2 + 2).toPointF()); } painter->setFont(font); - qt_draw_glyphs(painter, glyphs.constData(), positions.constData(), glyphs.size()); - - break; + QRawFont rawFont; + QRawFontPrivate *rawFontD = QRawFontPrivate::get(rawFont); + QFontPrivate *fontD = QFontPrivate::get(font); + rawFontD->fontEngine = fontD->engineForScript(QUnicodeTables::Common); + rawFontD->fontEngine->ref.ref(); + + QGlyphs glyphs; + glyphs.setFont(rawFont); + glyphs.setGlyphIndexes(glyphIndexes); + glyphs.setPositions(positions); + + painter->drawGlyphs(QPointF(), glyphs); + break; } +#endif case QPaintBufferPrivate::Cmd_DrawText: { QPointF pos(d->floats.at(cmd.extra), d->floats.at(cmd.extra+1)); diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp index 50d65e6..bef6b7d 100644 --- a/src/gui/painting/qpainter.cpp +++ b/src/gui/painting/qpainter.cpp @@ -75,6 +75,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -5790,12 +5791,14 @@ void QPainter::drawImage(const QRectF &targetRect, const QImage &image, const QR \sa QGlyphs::setFont(), QGlyphs::setPositions(), QGlyphs::setGlyphIndexes() */ +#if !defined(QT_NO_RAWFONT) void QPainter::drawGlyphs(const QPointF &position, const QGlyphs &glyphs) { Q_D(QPainter); - QFont oldFont = d->state->font; - d->state->font = glyphs.font(); + QRawFont font = glyphs.font(); + if (!font.isValid()) + return; QVector glyphIndexes = glyphs.glyphIndexes(); QVector glyphPositions = glyphs.positions(); @@ -5814,39 +5817,20 @@ void QPainter::drawGlyphs(const QPointF &position, const QGlyphs &glyphs) fixedPointPositions[i] = QFixedPoint::fromPointF(processedPosition); } - d->drawGlyphs(glyphIndexes.data(), fixedPointPositions.data(), count); - - d->state->font = oldFont; + d->drawGlyphs(glyphIndexes.data(), fixedPointPositions.data(), count, font, glyphs.overline(), + glyphs.underline(), glyphs.strikeOut()); } -void qt_draw_glyphs(QPainter *painter, const quint32 *glyphArray, const QPointF *positionArray, - int glyphCount) -{ - QVarLengthArray positions(glyphCount); - for (int i=0; idrawGlyphs(const_cast(glyphArray), positions.data(), glyphCount); -} - -void QPainterPrivate::drawGlyphs(quint32 *glyphArray, QFixedPoint *positions, int glyphCount) +void QPainterPrivate::drawGlyphs(quint32 *glyphArray, QFixedPoint *positions, int glyphCount, + const QRawFont &font, bool overline, bool underline, + bool strikeOut) { Q_Q(QPainter); updateState(state); - QFontEngine *fontEngine = state->font.d->engineForScript(QUnicodeTables::Common); - - while (fontEngine->type() == QFontEngine::Multi) { - // Pick engine based on first glyph in array if we are using a multi engine. - // (all glyphs must be for same font) - int engineIdx = 0; - if (glyphCount > 0) - engineIdx = glyphArray[0] >> 24; - - fontEngine = static_cast(fontEngine)->engine(engineIdx); - } + QRawFontPrivate *fontD = QRawFontPrivate::get(font); + QFontEngine *fontEngine = fontD->fontEngine; QFixed leftMost; QFixed rightMost; @@ -5881,7 +5865,6 @@ void QPainterPrivate::drawGlyphs(quint32 *glyphArray, QFixedPoint *positions, in extended->drawStaticTextItem(&staticTextItem); } else { QTextItemInt textItem; - textItem.f = &state->font; textItem.fontEngine = fontEngine; QVarLengthArray advances(glyphCount); @@ -5903,20 +5886,21 @@ void QPainterPrivate::drawGlyphs(quint32 *glyphArray, QFixedPoint *positions, in } QTextItemInt::RenderFlags flags; - if (state->font.underline()) + if (underline) flags |= QTextItemInt::Underline; - if (state->font.overline()) + if (overline) flags |= QTextItemInt::Overline; - if (state->font.strikeOut()) + if (strikeOut) flags |= QTextItemInt::StrikeOut; drawTextItemDecoration(q, QPointF(leftMost.toReal(), baseLine.toReal()), fontEngine, - (state->font.underline() - ? QTextCharFormat::SingleUnderline - : QTextCharFormat::NoUnderline), + (underline + ? QTextCharFormat::SingleUnderline + : QTextCharFormat::NoUnderline), flags, width.toReal(), QTextCharFormat()); } +#endif // QT_NO_RAWFONT /*! diff --git a/src/gui/painting/qpainter.h b/src/gui/painting/qpainter.h index ae2fdf2..4b2c447 100644 --- a/src/gui/painting/qpainter.h +++ b/src/gui/painting/qpainter.h @@ -399,7 +399,9 @@ public: void setLayoutDirection(Qt::LayoutDirection direction); Qt::LayoutDirection layoutDirection() const; +#if !defined(QT_NO_RAWFONT) void drawGlyphs(const QPointF &position, const QGlyphs &glyphs); +#endif void drawStaticText(const QPointF &topLeftPosition, const QStaticText &staticText); inline void drawStaticText(const QPoint &topLeftPosition, const QStaticText &staticText); diff --git a/src/gui/painting/qpainter_p.h b/src/gui/painting/qpainter_p.h index 26d8fc3..205c10a 100644 --- a/src/gui/painting/qpainter_p.h +++ b/src/gui/painting/qpainter_p.h @@ -184,6 +184,7 @@ struct QPainterDummyState QTransform transform; }; +class QRawFont; class QPainterPrivate { Q_DECLARE_PUBLIC(QPainter) @@ -229,7 +230,12 @@ public: void draw_helper(const QPainterPath &path, DrawOperation operation = StrokeAndFillDraw); void drawStretchedGradient(const QPainterPath &path, DrawOperation operation); void drawOpaqueBackground(const QPainterPath &path, DrawOperation operation); - void drawGlyphs(quint32 *glyphArray, QFixedPoint *positionArray, int glyphCount); + +#if !defined(QT_NO_RAWFONT) + void drawGlyphs(quint32 *glyphArray, QFixedPoint *positionArray, int glyphCount, + const QRawFont &font, bool overline = false, bool underline = false, + bool strikeOut = false); +#endif void updateMatrix(); void updateInvMatrix(); @@ -259,8 +265,6 @@ public: }; Q_GUI_EXPORT void qt_draw_helper(QPainterPrivate *p, const QPainterPath &path, QPainterPrivate::DrawOperation operation); -Q_GUI_EXPORT void qt_draw_glyphs(QPainter *painter, const quint32 *glyphArray, - const QPointF *positionArray, int glyphCount); QString qt_generate_brush_key(const QBrush &brush); diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp index f77e237..b8cfb1f 100644 --- a/src/gui/text/qfont.cpp +++ b/src/gui/text/qfont.cpp @@ -282,27 +282,16 @@ QFontPrivate::~QFontPrivate() scFont = 0; } -#if !defined(Q_WS_MAC) extern QMutex *qt_fontdatabase_mutex(); -QFontEngine *QFontPrivate::engineForScript(int script) const -{ - QMutexLocker locker(qt_fontdatabase_mutex()); - if (script >= QUnicodeTables::Inherited) - script = QUnicodeTables::Common; - if (engineData && engineData->fontCache != QFontCache::instance()) { - // throw out engineData that came from a different thread - engineData->ref.deref(); - engineData = 0; - } - if (!engineData || !engineData->engines[script]) - QFontDatabase::load(this, script); - return engineData->engines[script]; -} +#if !defined(Q_WS_MAC) +#define QT_FONT_ENGINE_FROM_DATA(data, script) data->engines[script] #else +#define QT_FONT_ENGINE_FROM_DATA(data, script) data->engine +#endif + QFontEngine *QFontPrivate::engineForScript(int script) const { - extern QMutex *qt_fontdatabase_mutex(); QMutexLocker locker(qt_fontdatabase_mutex()); if (script >= QUnicodeTables::Inherited) script = QUnicodeTables::Common; @@ -311,11 +300,10 @@ QFontEngine *QFontPrivate::engineForScript(int script) const engineData->ref.deref(); engineData = 0; } - if (!engineData || !engineData->engine) + if (!engineData || !QT_FONT_ENGINE_FROM_DATA(engineData, script)) QFontDatabase::load(this, script); - return engineData->engine; + return QT_FONT_ENGINE_FROM_DATA(engineData, script); } -#endif void QFontPrivate::alterCharForCapitalization(QChar &c) const { switch (capital) { diff --git a/src/gui/text/qfont_win.cpp b/src/gui/text/qfont_win.cpp index 7d710ea..3ef761b 100644 --- a/src/gui/text/qfont_win.cpp +++ b/src/gui/text/qfont_win.cpp @@ -58,6 +58,7 @@ QT_BEGIN_NAMESPACE extern HDC shared_dc(); // common dc for all fonts +extern QFont::Weight weightFromInteger(int weight); // qfontdatabase.cpp // ### maybe move to qapplication_win QFont qt_LOGFONTtoQFont(LOGFONT& lf, bool /*scale*/) @@ -65,20 +66,8 @@ QFont qt_LOGFONTtoQFont(LOGFONT& lf, bool /*scale*/) QString family = QString::fromWCharArray(lf.lfFaceName); QFont qf(family); qf.setItalic(lf.lfItalic); - if (lf.lfWeight != FW_DONTCARE) { - int weight; - if (lf.lfWeight < 400) - weight = QFont::Light; - else if (lf.lfWeight < 600) - weight = QFont::Normal; - else if (lf.lfWeight < 700) - weight = QFont::DemiBold; - else if (lf.lfWeight < 800) - weight = QFont::Bold; - else - weight = QFont::Black; - qf.setWeight(weight); - } + if (lf.lfWeight != FW_DONTCARE) + qf.setWeight(weightFromInteger(lf.lfWeight)); int lfh = qAbs(lf.lfHeight); qf.setPointSizeF(lfh * 72.0 / GetDeviceCaps(shared_dc(),LOGPIXELSY)); qf.setUnderline(false); diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp index 94f21b8..36b0ea9 100644 --- a/src/gui/text/qfontdatabase.cpp +++ b/src/gui/text/qfontdatabase.cpp @@ -136,6 +136,21 @@ static int getFontWeight(const QString &weightString) return (int) QFont::Normal; } +// convert 0 ~ 1000 integer to QFont::Weight +QFont::Weight weightFromInteger(int weight) +{ + if (weight < 400) + return QFont::Light; + else if (weight < 600) + return QFont::Normal; + else if (weight < 700) + return QFont::DemiBold; + else if (weight < 800) + return QFont::Bold; + else + return QFont::Black; +} + struct QtFontEncoding { signed int encoding : 16; @@ -497,8 +512,6 @@ QtFontFoundry *QtFontFamily::foundry(const QString &f, bool create) // ### copied to tools/makeqpf/qpf2.cpp -#if (defined(Q_WS_QWS) && !defined(QT_NO_FREETYPE)) || defined(Q_WS_WIN) || defined(Q_OS_SYMBIAN) || (defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA)) - // see the Unicode subset bitfields in the MSDN docs static int requiredUnicodeBits[QFontDatabase::WritingSystemsCount][2] = { // Any, @@ -576,7 +589,7 @@ static int requiredUnicodeBits[QFontDatabase::WritingSystemsCount][2] = { #define JapaneseCsbBit 17 #define KoreanCsbBit 21 -static QList determineWritingSystemsFromTrueTypeBits(quint32 unicodeRange[4], quint32 codePageRange[2]) +QList qt_determine_writing_systems_from_truetype_bits(quint32 unicodeRange[4], quint32 codePageRange[2]) { QList writingSystems; bool hasScript = false; @@ -623,7 +636,6 @@ static QList determineWritingSystemsFromTrueTypeBi return writingSystems; } -#endif #if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE) // class with virtual destructor, derived in qfontdatabase_s60.cpp @@ -873,7 +885,7 @@ QStringList QFontDatabasePrivate::addTTFile(const QByteArray &file, const QByteA os2->ulCodePageRange1, os2->ulCodePageRange2 }; - writingSystems = determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange); + writingSystems = qt_determine_writing_systems_from_truetype_bits(unicodeRange, codePageRange); //for (int i = 0; i < writingSystems.count(); ++i) // qDebug() << QFontDatabase::writingSystemName(writingSystems.at(i)); } @@ -936,6 +948,11 @@ static const int scriptForWritingSystem[] = { QUnicodeTables::Nko // Nko }; +int qt_script_for_writing_system(QFontDatabase::WritingSystem writingSystem) +{ + return scriptForWritingSystem[writingSystem]; +} + #if defined Q_WS_QWS || (defined(Q_WS_X11) && !defined(QT_NO_FONTCONFIG)) || defined(Q_WS_WIN) static inline bool requiresOpenType(int writingSystem) diff --git a/src/gui/text/qfontdatabase_mac.cpp b/src/gui/text/qfontdatabase_mac.cpp index ad2c1b2..5ba236b 100644 --- a/src/gui/text/qfontdatabase_mac.cpp +++ b/src/gui/text/qfontdatabase_mac.cpp @@ -72,7 +72,7 @@ static void initWritingSystems(QtFontFamily *family, ATSFontRef atsFont) qFromBigEndian(os2Table.data() + 54) }; quint32 codePageRange[2] = { qFromBigEndian(os2Table.data() + 78), qFromBigEndian(os2Table.data() + 82) }; - QList systems = determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange); + QList systems = qt_determine_writing_systems_from_truetype_bits(unicodeRange, codePageRange); #if 0 QCFString name; ATSFontGetName(atsFont, kATSOptionFlagsDefault, &name); @@ -244,6 +244,11 @@ static const char *styleHint(const QFontDef &request) return stylehint; } +static inline float weightToFloat(unsigned int weight) +{ + return (weight - 50) / 100.0; +} + void QFontDatabase::load(const QFontPrivate *d, int script) { // sanity checks diff --git a/src/gui/text/qfontdatabase_s60.cpp b/src/gui/text/qfontdatabase_s60.cpp index 6d3970e..1db4a7d 100644 --- a/src/gui/text/qfontdatabase_s60.cpp +++ b/src/gui/text/qfontdatabase_s60.cpp @@ -521,7 +521,7 @@ static bool registerScreenDeviceFont(int screenDeviceFontIndex, qFromBigEndian(ulCodePageRange + 4) }; const QList writingSystems = - determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange); + qt_determine_writing_systems_from_truetype_bits(unicodeRange, codePageRange); foreach (const QFontDatabase::WritingSystem system, writingSystems) family->writingSystems[system] = QtFontFamily::Supported; return true; diff --git a/src/gui/text/qfontdatabase_win.cpp b/src/gui/text/qfontdatabase_win.cpp index 8279195..05b7509 100644 --- a/src/gui/text/qfontdatabase_win.cpp +++ b/src/gui/text/qfontdatabase_win.cpp @@ -242,6 +242,8 @@ error: return i18n_name; } +extern QFont::Weight weightFromInteger(int weight); // qfontdatabase.cpp + static void addFontToDatabase(QString familyName, const QString &scriptName, TEXTMETRIC *textmetric, @@ -274,16 +276,7 @@ void addFontToDatabase(QString familyName, const QString &scriptName, if (familyName[0] != QLatin1Char('@') && !familyName.startsWith(QLatin1String("WST_"))) { QtFontStyle::Key styleKey; styleKey.style = italic ? QFont::StyleItalic : QFont::StyleNormal; - if (weight < 400) - styleKey.weight = QFont::Light; - else if (weight < 600) - styleKey.weight = QFont::Normal; - else if (weight < 700) - styleKey.weight = QFont::DemiBold; - else if (weight < 800) - styleKey.weight = QFont::Bold; - else - styleKey.weight = QFont::Black; + styleKey.weight = weightFromInteger(weight); QtFontFamily *family = privateDb()->family(familyName, true); @@ -340,7 +333,7 @@ void addFontToDatabase(QString familyName, const QString &scriptName, quint32 codePageRange[2] = { signature->fsCsb[0], signature->fsCsb[1] }; - QList systems = determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange); + QList systems = qt_determine_writing_systems_from_truetype_bits(unicodeRange, codePageRange); for (int i = 0; i < systems.count(); ++i) { QFontDatabase::WritingSystem writingSystem = systems.at(i); @@ -530,26 +523,26 @@ static inline void load(const QString &family = QString(), int = -1) -static void initFontInfo(QFontEngineWin *fe, const QFontDef &request, const QFontPrivate *fp) +static void initFontInfo(QFontEngineWin *fe, const QFontDef &request, HDC fontHdc, int dpi) { fe->fontDef = request; // most settings are equal - HDC dc = ((request.styleStrategy & QFont::PreferDevice) && fp->hdc) ? fp->hdc : shared_dc(); + HDC dc = ((request.styleStrategy & QFont::PreferDevice) && fontHdc) ? fontHdc : shared_dc(); SelectObject(dc, fe->hfont); wchar_t n[64]; GetTextFace(dc, 64, n); fe->fontDef.family = QString::fromWCharArray(n); fe->fontDef.fixedPitch = !(fe->tm.tmPitchAndFamily & TMPF_FIXED_PITCH); if (fe->fontDef.pointSize < 0) { - fe->fontDef.pointSize = fe->fontDef.pixelSize * 72. / fp->dpi; + fe->fontDef.pointSize = fe->fontDef.pixelSize * 72. / dpi; } else if (fe->fontDef.pixelSize == -1) { - fe->fontDef.pixelSize = qRound(fe->fontDef.pointSize * fp->dpi / 72.); + fe->fontDef.pixelSize = qRound(fe->fontDef.pointSize * dpi / 72.); } } #if !defined(QT_NO_DIRECTWRITE) static void initFontInfo(QFontEngineDirectWrite *fe, const QFontDef &request, - const QFontPrivate *fp, IDWriteFont *font) + int dpi, IDWriteFont *font) { fe->fontDef = request; @@ -601,9 +594,9 @@ static void initFontInfo(QFontEngineDirectWrite *fe, const QFontDef &request, qErrnoWarning(hr, "initFontInfo: Failed to get family name"); if (fe->fontDef.pointSize < 0) - fe->fontDef.pointSize = fe->fontDef.pixelSize * 72. / fp->dpi; + fe->fontDef.pointSize = fe->fontDef.pixelSize * 72. / dpi; else if (fe->fontDef.pixelSize == -1) - fe->fontDef.pixelSize = qRound(fe->fontDef.pointSize * fp->dpi / 72.); + fe->fontDef.pixelSize = qRound(fe->fontDef.pointSize * dpi / 72.); } #endif @@ -679,20 +672,21 @@ static inline HFONT systemFont() #define DEFAULT_GUI_FONT 17 #endif -static -QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &request, const QtFontDesc *desc, - const QStringList &family_list) +static QFontEngine *loadEngine(int script, const QFontDef &request, + HDC fontHdc, int dpi, bool rawMode, + const QtFontDesc *desc, + const QStringList &family_list) { LOGFONT lf; memset(&lf, 0, sizeof(LOGFONT)); - bool useDevice = (request.styleStrategy & QFont::PreferDevice) && fp->hdc; + bool useDevice = (request.styleStrategy & QFont::PreferDevice) && fontHdc; HDC hdc = shared_dc(); - QString font_name = desc->family->name; + QString font_name = desc != 0 ? desc->family->name : request.family; if (useDevice) { - hdc = fp->hdc; + hdc = fontHdc; font_name = request.family; } @@ -710,9 +704,9 @@ QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &requ bool useDirectWrite = false; #endif - if (fp->rawMode) { // will choose a stock font + if (rawMode) { // will choose a stock font int f, deffnt = SYSTEM_FONT; - QString fam = desc->family->name.toLower(); + QString fam = desc != 0 ? desc->family->name.toLower() : request.family.toLower(); if (fam == QLatin1String("default")) f = deffnt; else if (fam == QLatin1String("system")) @@ -766,11 +760,11 @@ QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &requ lf.lfWidth = 0; lf.lfEscapement = 0; lf.lfOrientation = 0; - if (desc->style->key.weight == 50) + if (desc == 0 || desc->style->key.weight == 50) lf.lfWeight = FW_DONTCARE; else lf.lfWeight = (desc->style->key.weight*900)/99; - lf.lfItalic = (desc->style->key.style != QFont::StyleNormal); + lf.lfItalic = (desc != 0 && desc->style->key.style != QFont::StyleNormal); lf.lfCharSet = DEFAULT_CHARSET; int strat = OUT_DEFAULT_PRECIS; @@ -901,9 +895,11 @@ QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &requ &lf, &directWriteFont); if (FAILED(hr)) { +#ifndef QT_NO_DEBUG qErrnoWarning("QFontEngine::loadEngine: CreateFontFromLOGFONT failed " "for %ls (0x%lx)", lf.lfFaceName, hr); +#endif } else { DeleteObject(hfont); useDirectWrite = true; @@ -933,22 +929,27 @@ QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &requ } } - initFontInfo(few, request, fp); + initFontInfo(few, request, fontHdc, dpi); fe = few; } #if !defined(QT_NO_DIRECTWRITE) else { QFontDatabasePrivate *db = privateDb(); - QFontEngineDirectWrite *fedw = new QFontEngineDirectWrite(font_name, - db->directWriteFactory, - db->directWriteGdiInterop, - directWriteFont, - request.pixelSize); - initFontInfo(fedw, request, fp, directWriteFont); + IDWriteFontFace *directWriteFontFace = NULL; + HRESULT hr = directWriteFont->CreateFontFace(&directWriteFontFace); + if (SUCCEEDED(hr)) { + QFontEngineDirectWrite *fedw = new QFontEngineDirectWrite(db->directWriteFactory, + directWriteFontFace, + request.pixelSize); + + initFontInfo(fedw, request, dpi, directWriteFont); - fe = fedw; + fe = fedw; + } else { + qErrnoWarning(hr, "QFontEngine::loadEngine: CreateFontFace failed"); + } } if (directWriteFont != 0) @@ -957,6 +958,7 @@ QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &requ if(script == QUnicodeTables::Common && !(request.styleStrategy & QFont::NoFontMerging) + && desc != 0 && !(desc->family->writingSystems[QFontDatabase::Symbol] & QtFontFamily::Supported)) { if(!tryFonts) { LANGID lid = GetUserDefaultLangID(); @@ -993,6 +995,20 @@ QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &requ return fe; } +QFontEngine *qt_load_font_engine_win(const QFontDef &request) +{ + // From qfont.cpp + extern int qt_defaultDpi(); + + QFontCache::Key key(request, QUnicodeTables::Common); + QFontEngine *fe = QFontCache::instance()->findEngine(key); + if (fe != 0) + return fe; + else + return loadEngine(QUnicodeTables::Common, request, 0, qt_defaultDpi(), false, 0, + QStringList()); +} + const char *styleHint(const QFontDef &request) { const char *stylehint = 0; @@ -1053,7 +1069,7 @@ static QFontEngine *loadWin(const QFontPrivate *d, int script, const QFontDef &r } if (!desc.family) break; - fe = loadEngine(script, d, req, &desc, family_list); + fe = loadEngine(script, req, d->hdc, d->dpi, d->rawMode, &desc, family_list); if (!fe) blacklistedFamilies.append(desc.familyIndex); } diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index 3adf4eb..2f76cc6 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -237,24 +237,6 @@ glyph_metrics_t QFontEngine::boundingBox(glyph_t glyph, const QTransform &matrix return metrics; } -QFont QFontEngine::createExplicitFont() const -{ - return createExplicitFontWithName(fontDef.family); -} - -QFont QFontEngine::createExplicitFontWithName(const QString &familyName) const -{ - QFont font(familyName); - font.setStyleStrategy(QFont::NoFontMerging); - font.setWeight(fontDef.weight); - font.setItalic(fontDef.style == QFont::StyleItalic); - if (fontDef.pointSize < 0) - font.setPixelSize(fontDef.pixelSize); - else - font.setPointSizeF(fontDef.pointSize); - return font; -} - QFixed QFontEngine::xHeight() const { QGlyphLayoutArray<8> glyphs; diff --git a/src/gui/text/qfontengine_coretext.mm b/src/gui/text/qfontengine_coretext.mm index 4d9192e..20b3730 100644 --- a/src/gui/text/qfontengine_coretext.mm +++ b/src/gui/text/qfontengine_coretext.mm @@ -52,6 +52,31 @@ QT_BEGIN_NAMESPACE static float SYNTHETIC_ITALIC_SKEW = tanf(14 * acosf(0) / 90); +static void loadAdvancesForGlyphs(CTFontRef ctfont, + QVarLengthArray &cgGlyphs, + QGlyphLayout *glyphs, int len, + QTextEngine::ShaperFlags flags, + const QFontDef &fontDef) +{ + Q_UNUSED(flags); + QVarLengthArray advances(len); + CTFontGetAdvancesForGlyphs(ctfont, kCTFontHorizontalOrientation, cgGlyphs.data(), advances.data(), len); + + for (int i = 0; i < len; ++i) { + if (glyphs->glyphs[i] & 0xff000000) + continue; + glyphs->advances_x[i] = QFixed::fromReal(advances[i].width); + glyphs->advances_y[i] = QFixed::fromReal(advances[i].height); + } + + if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) { + for (int i = 0; i < len; ++i) { + glyphs->advances_x[i] = glyphs->advances_x[i].round(); + glyphs->advances_y[i] = glyphs->advances_y[i].round(); + } + } +} + QCoreTextFontEngineMulti::QCoreTextFontEngineMulti(const QCFString &name, const QFontDef &fontDef, bool kerning) : QFontEngineMulti(0) { @@ -83,7 +108,31 @@ QCoreTextFontEngineMulti::QCoreTextFontEngineMulti(const QCFString &name, const ctfont = baseFont; CFRetain(ctfont); } + init(kerning); +} + +QCoreTextFontEngineMulti::QCoreTextFontEngineMulti(CGFontRef cgFontRef, const QFontDef &fontDef, bool kerning) + : QFontEngineMulti(0) +{ + this->fontDef = fontDef; + + transform = CGAffineTransformIdentity; + if (fontDef.stretch != 100) { + transform = CGAffineTransformMakeScale(float(fontDef.stretch) / float(100), 1); + } + + ctfont = CTFontCreateWithGraphicsFont(cgFontRef, fontDef.pixelSize, &transform, NULL); + init(kerning); +} + +QCoreTextFontEngineMulti::~QCoreTextFontEngineMulti() +{ + CFRelease(ctfont); +} +void QCoreTextFontEngineMulti::init(bool kerning) +{ + Q_ASSERT(ctfont != NULL); attributeDict = CFDictionaryCreateMutable(0, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); @@ -94,26 +143,20 @@ QCoreTextFontEngineMulti::QCoreTextFontEngineMulti(const QCFString &name, const CFDictionaryAddValue(attributeDict, kCTKernAttributeName, noKern); } - QCoreTextFontEngine *fe = new QCoreTextFontEngine(ctfont, fontDef, this); + QCoreTextFontEngine *fe = new QCoreTextFontEngine(ctfont, fontDef); fe->ref.ref(); engines.append(fe); - -} - -QCoreTextFontEngineMulti::~QCoreTextFontEngineMulti() -{ - CFRelease(ctfont); } -uint QCoreTextFontEngineMulti::fontIndexForFont(CTFontRef id) const +uint QCoreTextFontEngineMulti::fontIndexForFont(CTFontRef font) const { for (int i = 0; i < engines.count(); ++i) { - if (CFEqual(engineAt(i)->ctfont, id)) + if (CFEqual(engineAt(i)->ctfont, font)) return i; } QCoreTextFontEngineMulti *that = const_cast(this); - QCoreTextFontEngine *fe = new QCoreTextFontEngine(id, fontDef, that); + QCoreTextFontEngine *fe = new QCoreTextFontEngine(font, fontDef); fe->ref.ref(); that->engines.append(fe); return engines.count() - 1; @@ -317,72 +360,45 @@ bool QCoreTextFontEngineMulti::stringToCMap(const QChar *str, int len, QGlyphLay if (flags & QTextEngine::GlyphIndicesOnly) return true; - QVarLengthArray advances(len); - CTFontGetAdvancesForGlyphs(ctfont, kCTFontHorizontalOrientation, cgGlyphs.data(), advances.data(), len); - - for (int i = 0; i < len; ++i) { - if (glyphs->glyphs[i] & 0xff000000) - continue; - glyphs->advances_x[i] = QFixed::fromReal(advances[i].width); - glyphs->advances_y[i] = QFixed::fromReal(advances[i].height); - } - - if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) { - for (int i = 0; i < len; ++i) { - glyphs->advances_x[i] = glyphs->advances_x[i].round(); - glyphs->advances_y[i] = glyphs->advances_y[i].round(); - } - } - + loadAdvancesForGlyphs(ctfont, cgGlyphs, glyphs, len, flags, fontDef); return true; } -void QCoreTextFontEngineMulti::recalcAdvances(int , QGlyphLayout *, QTextEngine::ShaperFlags) const -{ -} -void QCoreTextFontEngineMulti::doKerning(int , QGlyphLayout *, QTextEngine::ShaperFlags) const -{ -} - void QCoreTextFontEngineMulti::loadEngine(int) { // Do nothing Q_ASSERT(false); } +extern int qt_antialiasing_threshold; // from qapplication.cpp +static inline CGAffineTransform transformFromFontDef(const QFontDef &fontDef) +{ + CGAffineTransform transform = CGAffineTransformIdentity; + if (fontDef.stretch != 100) + transform = CGAffineTransformMakeScale(float(fontDef.stretch) / float(100), 1); + return transform; +} -QCoreTextFontEngine::QCoreTextFontEngine(CTFontRef font, const QFontDef &def, - QCoreTextFontEngineMulti *multiEngine) +QCoreTextFontEngine::QCoreTextFontEngine(CTFontRef font, const QFontDef &def) { fontDef = def; - parentEngine = multiEngine; - synthesisFlags = 0; + transform = transformFromFontDef(fontDef); ctfont = font; CFRetain(ctfont); - cgFont = CTFontCopyGraphicsFont(ctfont, NULL); - CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(ctfont); - if (fontDef.weight >= QFont::Bold && !(traits & kCTFontBoldTrait)) { - synthesisFlags |= SynthesizedBold; - } - - if (fontDef.style != QFont::StyleNormal && !(traits & kCTFontItalicTrait)) { - synthesisFlags |= SynthesizedItalic; - } - transform = CGAffineTransformIdentity; - if (fontDef.stretch != 100) { - transform = CGAffineTransformMakeScale(float(fontDef.stretch) / float(100), 1); - } - QByteArray os2Table = getSfntTable(MAKE_TAG('O', 'S', '/', '2')); - if (os2Table.size() >= 10) - fsType = qFromBigEndian(reinterpret_cast(os2Table.constData() + 8)); + cgFont = CTFontCopyGraphicsFont(font, NULL); + init(); +} - QSettings appleSettings(QLatin1String("apple.com")); - QVariant appleValue = appleSettings.value(QLatin1String("AppleAntiAliasingThreshold")); - if (appleValue.isValid()) - antialiasing_threshold = appleValue.toInt(); - else - antialiasing_threshold = -1; +QCoreTextFontEngine::QCoreTextFontEngine(CGFontRef font, const QFontDef &def) +{ + fontDef = def; + transform = transformFromFontDef(fontDef); + cgFont = font; + // Keep reference count balanced + CFRetain(cgFont); + ctfont = CTFontCreateWithGraphicsFont(font, fontDef.pixelSize, &transform, NULL); + init(); } QCoreTextFontEngine::~QCoreTextFontEngine() @@ -391,9 +407,89 @@ QCoreTextFontEngine::~QCoreTextFontEngine() CFRelease(ctfont); } -bool QCoreTextFontEngine::stringToCMap(const QChar *, int, QGlyphLayout *, int *, QTextEngine::ShaperFlags) const +extern QFont::Weight weightFromInteger(int weight); // qfontdatabase.cpp + +int getTraitValue(CFDictionaryRef allTraits, CFStringRef trait) { - return false; + if (CFDictionaryContainsKey(allTraits, trait)) { + CFNumberRef traitNum = (CFNumberRef) CFDictionaryGetValue(allTraits, trait); + float v = 0; + CFNumberGetValue(traitNum, kCFNumberFloatType, &v); + // the value we get from CFNumberRef is from -1.0 to 1.0 + int value = v * 500 + 500; + return value; + } + + return 0; +} + +void QCoreTextFontEngine::init() +{ + Q_ASSERT(ctfont != NULL); + Q_ASSERT(cgFont != NULL); + + QCFString family = CTFontCopyFamilyName(ctfont); + fontDef.family = family; + + synthesisFlags = 0; + CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(ctfont); + if (traits & kCTFontItalicTrait) + fontDef.style = QFont::StyleItalic; + + CFDictionaryRef allTraits = CTFontCopyTraits(ctfont); + fontDef.weight = weightFromInteger(getTraitValue(allTraits, kCTFontWeightTrait)); + int slant = getTraitValue(allTraits, kCTFontSlantTrait); + if (slant > 500 && !(traits & kCTFontItalicTrait)) + fontDef.style = QFont::StyleOblique; + CFRelease(allTraits); + + if (fontDef.weight >= QFont::Bold && !(traits & kCTFontBoldTrait)) + synthesisFlags |= SynthesizedBold; + // XXX: we probably don't need to synthesis italic for oblique font + if (fontDef.style != QFont::StyleNormal && !(traits & kCTFontItalicTrait)) + synthesisFlags |= SynthesizedItalic; + + avgCharWidth = 0; + QByteArray os2Table = getSfntTable(MAKE_TAG('O', 'S', '/', '2')); + unsigned emSize = CTFontGetUnitsPerEm(ctfont); + if (os2Table.size() >= 10) { + fsType = qFromBigEndian(reinterpret_cast(os2Table.constData() + 8)); + // qAbs is a workaround for weird fonts like Lucida Grande + qint16 width = qAbs(qFromBigEndian(reinterpret_cast(os2Table.constData() + 2))); + avgCharWidth = QFixed::fromReal(width * fontDef.pixelSize / emSize); + } else + avgCharWidth = QFontEngine::averageCharWidth(); + + ctMaxCharWidth = ctMinLeftBearing = ctMinRightBearing = 0; + QByteArray hheaTable = getSfntTable(MAKE_TAG('h', 'h', 'e', 'a')); + if (hheaTable.size() >= 16) { + quint16 width = qFromBigEndian(reinterpret_cast(hheaTable.constData() + 10)); + ctMaxCharWidth = width * fontDef.pixelSize / emSize; + qint16 bearing = qFromBigEndian(reinterpret_cast(hheaTable.constData() + 12)); + ctMinLeftBearing = bearing * fontDef.pixelSize / emSize; + bearing = qFromBigEndian(reinterpret_cast(hheaTable.constData() + 14)); + ctMinRightBearing = bearing * fontDef.pixelSize / emSize; + } +} + +bool QCoreTextFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, + int *nglyphs, QTextEngine::ShaperFlags flags) const +{ + *nglyphs = len; + QCFType cfstring; + + QVarLengthArray cgGlyphs(len); + CTFontGetGlyphsForCharacters(ctfont, (const UniChar*)str, cgGlyphs.data(), len); + + for (int i = 0; i < len; ++i) + if (cgGlyphs[i]) + glyphs->glyphs[i] = cgGlyphs[i]; + + if (flags & QTextEngine::GlyphIndicesOnly) + return true; + + loadAdvancesForGlyphs(ctfont, cgGlyphs, glyphs, len, flags, fontDef); + return true; } glyph_metrics_t QCoreTextFontEngine::boundingBox(const QGlyphLayout &glyphs) @@ -407,6 +503,7 @@ glyph_metrics_t QCoreTextFontEngine::boundingBox(const QGlyphLayout &glyphs) } return glyph_metrics_t(0, -(ascent()), w - lastRightBearing(glyphs, round), ascent()+descent(), w, 0); } + glyph_metrics_t QCoreTextFontEngine::boundingBox(glyph_t glyph) { glyph_metrics_t ret; @@ -460,31 +557,29 @@ QFixed QCoreTextFontEngine::xHeight() const ? QFixed::fromReal(CTFontGetXHeight(ctfont)).round() : QFixed::fromReal(CTFontGetXHeight(ctfont)); } + QFixed QCoreTextFontEngine::averageCharWidth() const { - // ### Need to implement properly and get the information from the OS/2 Table. return (fontDef.styleStrategy & QFont::ForceIntegerMetrics) - ? QFontEngine::averageCharWidth().round() - : QFontEngine::averageCharWidth(); + ? avgCharWidth.round() : avgCharWidth; } qreal QCoreTextFontEngine::maxCharWidth() const { - // ### Max Help! - return 0; - + return (fontDef.styleStrategy & QFont::ForceIntegerMetrics) + ? qRound(ctMaxCharWidth) : ctMaxCharWidth; } + qreal QCoreTextFontEngine::minLeftBearing() const { - // ### Min Help! - return 0; - + return (fontDef.styleStrategy & QFont::ForceIntegerMetrics) + ? qRound(ctMinLeftBearing) : ctMinLeftBearing; } + qreal QCoreTextFontEngine::minRightBearing() const { - // ### Max Help! (even thought it's right) - return 0; - + return (fontDef.styleStrategy & QFont::ForceIntegerMetrics) + ? qRound(ctMinRightBearing) : ctMinLeftBearing; } void QCoreTextFontEngine::draw(CGContextRef ctx, qreal x, qreal y, const QTextItemInt &ti, int paintDeviceHeight) @@ -602,12 +697,6 @@ void QCoreTextFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *position } } -QFont QCoreTextFontEngine::createExplicitFont() const -{ - QString familyName = QCFString::toQString(CTFontCopyFamilyName(ctfont)); - return createExplicitFontWithName(familyName); -} - QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition, int /*margin*/, bool aa) { const glyph_metrics_t br = boundingBox(glyph); @@ -624,7 +713,7 @@ QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition cgflags); CGContextSetFontSize(ctx, fontDef.pixelSize); CGContextSetShouldAntialias(ctx, aa || - (fontDef.pointSize > antialiasing_threshold + (fontDef.pointSize > qt_antialiasing_threshold && !(fontDef.styleStrategy & QFont::NoAntialias))); CGContextSetShouldSmoothFonts(ctx, aa); CGAffineTransform oldTextMatrix = CGContextGetTextMatrix(ctx); @@ -696,12 +785,19 @@ QImage QCoreTextFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed subPixelPo return im; } -void QCoreTextFontEngine::recalcAdvances(int numGlyphs, QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const +void QCoreTextFontEngine::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const { - Q_ASSERT(false); - Q_UNUSED(numGlyphs); - Q_UNUSED(glyphs); - Q_UNUSED(flags); + int i, numGlyphs = glyphs->numGlyphs; + QVarLengthArray cgGlyphs(numGlyphs); + + for (i = 0; i < numGlyphs; ++i) { + if (glyphs->glyphs[i] & 0xff000000) + cgGlyphs[i] = 0; + else + cgGlyphs[i] = glyphs->glyphs[i]; + } + + loadAdvancesForGlyphs(ctfont, cgGlyphs, glyphs, numGlyphs, flags, fontDef); } QFontEngine::FaceId QCoreTextFontEngine::faceId() const @@ -711,36 +807,36 @@ QFontEngine::FaceId QCoreTextFontEngine::faceId() const bool QCoreTextFontEngine::canRender(const QChar *string, int len) { - QCFType retFont = CTFontCreateForString(ctfont, - QCFType(CFStringCreateWithCharactersNoCopy(0, - reinterpret_cast(string), - len, kCFAllocatorNull)), - CFRangeMake(0, len)); - return retFont != 0; - return false; -} - - bool QCoreTextFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const - { - QCFType table = CTFontCopyTable(ctfont, tag, 0); - if (!table || !length) - return false; - CFIndex tableLength = CFDataGetLength(table); - int availableLength = *length; - *length = tableLength; - if (buffer) { - if (tableLength > availableLength) - return false; - CFDataGetBytes(table, CFRangeMake(0, tableLength), buffer); - } - return true; - } + QVarLengthArray cgGlyphs(len); + return CTFontGetGlyphsForCharacters(ctfont, (const UniChar *) string, cgGlyphs.data(), len); +} + +bool QCoreTextFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const +{ + QCFType table = CTFontCopyTable(ctfont, tag, 0); + if (!table || !length) + return false; + CFIndex tableLength = CFDataGetLength(table); + int availableLength = *length; + *length = tableLength; + if (buffer) { + if (tableLength > availableLength) + return false; + CFDataGetBytes(table, CFRangeMake(0, tableLength), buffer); + } + return true; +} void QCoreTextFontEngine::getUnscaledGlyph(glyph_t, QPainterPath *, glyph_metrics_t *) { // ### } +QFixed QCoreTextFontEngine::emSquareSize() const +{ + return QFixed::QFixed(int(CTFontGetUnitsPerEm(ctfont))); +} + QT_END_NAMESPACE #endif// !defined(Q_WS_MAC) || (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) diff --git a/src/gui/text/qfontengine_coretext_p.h b/src/gui/text/qfontengine_coretext_p.h index 7d17aef..1503c3f 100644 --- a/src/gui/text/qfontengine_coretext_p.h +++ b/src/gui/text/qfontengine_coretext_p.h @@ -46,15 +46,17 @@ #if !defined(Q_WS_MAC) || (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) +class QRawFontPrivate; class QCoreTextFontEngineMulti; class QCoreTextFontEngine : public QFontEngine { public: - QCoreTextFontEngine(CTFontRef font, const QFontDef &def, - QCoreTextFontEngineMulti *multiEngine = 0); + QCoreTextFontEngine(CTFontRef font, const QFontDef &def); + QCoreTextFontEngine(CGFontRef font, const QFontDef &def); ~QCoreTextFontEngine(); + virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const; - virtual void recalcAdvances(int , QGlyphLayout *, QTextEngine::ShaperFlags) const; + virtual void recalcAdvances(QGlyphLayout *, QTextEngine::ShaperFlags) const; virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs); virtual glyph_metrics_t boundingBox(glyph_t glyph); @@ -87,23 +89,29 @@ public: virtual QImage alphaRGBMapForGlyph(glyph_t, QFixed subPixelPosition, int margin, const QTransform &t); virtual qreal minRightBearing() const; virtual qreal minLeftBearing() const; - virtual QFont createExplicitFont() const; + virtual QFixed emSquareSize() const; private: + friend class QRawFontPrivate; + + void init(); QImage imageForGlyph(glyph_t glyph, QFixed subPixelPosition, int margin, bool colorful); CTFontRef ctfont; CGFontRef cgFont; - QCoreTextFontEngineMulti *parentEngine; int synthesisFlags; CGAffineTransform transform; + QFixed avgCharWidth; + qreal ctMaxCharWidth; + qreal ctMinLeftBearing; + qreal ctMinRightBearing; friend class QCoreTextFontEngineMulti; - int antialiasing_threshold; }; class QCoreTextFontEngineMulti : public QFontEngineMulti { public: QCoreTextFontEngineMulti(const QCFString &name, const QFontDef &fontDef, bool kerning); + QCoreTextFontEngineMulti(CGFontRef cgFontRef, const QFontDef &fontDef, bool kerning); ~QCoreTextFontEngineMulti(); virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, @@ -112,19 +120,16 @@ public: QTextEngine::ShaperFlags flags, unsigned short *logClusters, const HB_CharAttributes *charAttributes) const; - - virtual void recalcAdvances(int , QGlyphLayout *, QTextEngine::ShaperFlags) const; - virtual void doKerning(int , QGlyphLayout *, QTextEngine::ShaperFlags) const; - virtual const char *name() const { return "CoreText"; } protected: virtual void loadEngine(int at); private: + void init(bool kerning); inline const QCoreTextFontEngine *engineAt(int i) const { return static_cast(engines.at(i)); } - uint fontIndexForFont(CTFontRef id) const; + uint fontIndexForFont(CTFontRef font) const; CTFontRef ctfont; mutable QCFType attributeDict; CGAffineTransform transform; diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp index ffdaaa7..8f2da9b 100644 --- a/src/gui/text/qfontengine_ft.cpp +++ b/src/gui/text/qfontengine_ft.cpp @@ -200,9 +200,10 @@ HB_Error QFreetypeFace::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 p * Returns the freetype face or 0 in case of an empty file or any other problems * (like not being able to open the file) */ -QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id) +QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id, + const QByteArray &fontData) { - if (face_id.filename.isEmpty()) + if (face_id.filename.isEmpty() && fontData.isEmpty()) return 0; QtFreetypeData *freetypeData = qt_getFreetypeData(); @@ -215,21 +216,25 @@ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id) } else { QScopedPointer newFreetype(new QFreetypeFace); FT_Face face; - QFile file(QString::fromUtf8(face_id.filename)); - if (face_id.filename.startsWith(":qmemoryfonts/")) { - // from qfontdatabase.cpp - extern QByteArray qt_fontdata_from_index(int); - QByteArray idx = face_id.filename; - idx.remove(0, 14); // remove ':qmemoryfonts/' - bool ok = false; - newFreetype->fontData = qt_fontdata_from_index(idx.toInt(&ok)); - if (!ok) - newFreetype->fontData = QByteArray(); - } else if (!(file.fileEngine()->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::LocalDiskFlag)) { - if (!file.open(QIODevice::ReadOnly)) { - return 0; + if (!face_id.filename.isEmpty()) { + QFile file(QString::fromUtf8(face_id.filename)); + if (face_id.filename.startsWith(":qmemoryfonts/")) { + // from qfontdatabase.cpp + extern QByteArray qt_fontdata_from_index(int); + QByteArray idx = face_id.filename; + idx.remove(0, 14); // remove ':qmemoryfonts/' + bool ok = false; + newFreetype->fontData = qt_fontdata_from_index(idx.toInt(&ok)); + if (!ok) + newFreetype->fontData = QByteArray(); + } else if (!(file.fileEngine()->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::LocalDiskFlag)) { + if (!file.open(QIODevice::ReadOnly)) { + return 0; + } + newFreetype->fontData = file.readAll(); } - newFreetype->fontData = file.readAll(); + } else { + newFreetype->fontData = fontData; } if (!newFreetype->fontData.isEmpty()) { if (FT_New_Memory_Face(freetypeData->library, (const FT_Byte *)newFreetype->fontData.constData(), newFreetype->fontData.size(), face_id.index, &face)) { @@ -651,8 +656,21 @@ void QFontEngineFT::freeGlyphSets() freeServerGlyphSet(transformedGlyphSets.at(i).id); } -bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format) +bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format, + const QByteArray &fontData) { + return init(faceId, antialias, format, QFreetypeFace::getFace(faceId, fontData)); +} + +bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format, + QFreetypeFace *freetypeFace) +{ + freetype = freetypeFace; + if (!freetype) { + xsize = 0; + ysize = 0; + return false; + } defaultFormat = format; this->antialias = antialias; @@ -664,12 +682,6 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format) glyphFormat = QFontEngineGlyphCache::Raster_RGBMask; face_id = faceId; - freetype = QFreetypeFace::getFace(face_id); - if (!freetype) { - xsize = 0; - ysize = 0; - return false; - } symbol = freetype->symbol_map != 0; PS_FontInfoRec psrec; @@ -791,6 +803,106 @@ int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags, return load_flags; } +QFontEngineFT::Glyph *QFontEngineFT::loadGlyphMetrics(QGlyphSet *set, uint glyph, GlyphFormat format) const +{ + Glyph *g = set->getGlyph(glyph); + if (g && g->format == format) + return g; + + bool hsubpixel = false; + int vfactor = 1; + int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor); + + // apply our matrix to this, but note that the metrics will not be affected by this. + FT_Face face = lockFace(); + FT_Matrix matrix = this->matrix; + FT_Matrix_Multiply(&set->transformationMatrix, &matrix); + FT_Set_Transform(face, &matrix, 0); + freetype->matrix = matrix; + + bool transform = matrix.xx != 0x10000 || matrix.yy != 0x10000 || matrix.xy != 0 || matrix.yx != 0; + if (transform) + load_flags |= FT_LOAD_NO_BITMAP; + + FT_Error err = FT_Load_Glyph(face, glyph, load_flags); + if (err && (load_flags & FT_LOAD_NO_BITMAP)) { + load_flags &= ~FT_LOAD_NO_BITMAP; + err = FT_Load_Glyph(face, glyph, load_flags); + } + if (err == FT_Err_Too_Few_Arguments) { + // this is an error in the bytecode interpreter, just try to run without it + load_flags |= FT_LOAD_FORCE_AUTOHINT; + err = FT_Load_Glyph(face, glyph, load_flags); + } + if (err != FT_Err_Ok) + qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph); + + unlockFace(); + if (set->outline_drawing) + return 0; + + if (!g) { + g = new Glyph; + g->uploadedToServer = false; + g->data = 0; + } + + FT_GlyphSlot slot = face->glyph; + if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(slot); + int left = slot->metrics.horiBearingX; + int right = slot->metrics.horiBearingX + slot->metrics.width; + int top = slot->metrics.horiBearingY; + int bottom = slot->metrics.horiBearingY - slot->metrics.height; + if (transform && slot->format != FT_GLYPH_FORMAT_BITMAP) { // freetype doesn't apply the transformation on the metrics + int l, r, t, b; + FT_Vector vector; + vector.x = left; + vector.y = top; + FT_Vector_Transform(&vector, &matrix); + l = r = vector.x; + t = b = vector.y; + vector.x = right; + vector.y = top; + FT_Vector_Transform(&vector, &matrix); + if (l > vector.x) l = vector.x; + if (r < vector.x) r = vector.x; + if (t < vector.y) t = vector.y; + if (b > vector.y) b = vector.y; + vector.x = right; + vector.y = bottom; + FT_Vector_Transform(&vector, &matrix); + if (l > vector.x) l = vector.x; + if (r < vector.x) r = vector.x; + if (t < vector.y) t = vector.y; + if (b > vector.y) b = vector.y; + vector.x = left; + vector.y = bottom; + FT_Vector_Transform(&vector, &matrix); + if (l > vector.x) l = vector.x; + if (r < vector.x) r = vector.x; + if (t < vector.y) t = vector.y; + if (b > vector.y) b = vector.y; + left = l; + right = r; + top = t; + bottom = b; + } + left = FLOOR(left); + right = CEIL(right); + bottom = FLOOR(bottom); + top = CEIL(top); + + g->linearAdvance = face->glyph->linearHoriAdvance >> 10; + g->width = TRUNC(right-left); + g->height = TRUNC(top-bottom); + g->x = TRUNC(left); + g->y = TRUNC(top); + g->advance = TRUNC(ROUND(face->glyph->advance.x)); + g->format = Format_None; + + return g; +} + QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph, QFixed subPixelPosition, GlyphFormat format, @@ -1511,7 +1623,7 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs mtx->lock(); } - if (FcCharSetHasChar(freetype->charset, uc)) { + if (freetype->charset != 0 && FcCharSetHasChar(freetype->charset, uc)) { #else if (false) { #endif @@ -1546,7 +1658,7 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs mtx->lock(); } - if (FcCharSetHasChar(freetype->charset, uc)) + if (freetype->charset == 0 || FcCharSetHasChar(freetype->charset, uc)) #endif { redo: diff --git a/src/gui/text/qfontengine_ft_p.h b/src/gui/text/qfontengine_ft_p.h index 451d26e..887efed 100644 --- a/src/gui/text/qfontengine_ft_p.h +++ b/src/gui/text/qfontengine_ft_p.h @@ -74,6 +74,8 @@ QT_BEGIN_NAMESPACE +class QFontEngineFTRawFont; + /* * This struct represents one font file on disk (like Arial.ttf) and is shared between all the font engines * that show this font file (at different pixel sizes). @@ -84,7 +86,8 @@ struct QFreetypeFace QFontEngine::Properties properties() const; bool getSfntTable(uint tag, uchar *buffer, uint *length) const; - static QFreetypeFace *getFace(const QFontEngine::FaceId &face_id); + static QFreetypeFace *getFace(const QFontEngine::FaceId &face_id, + const QByteArray &fontData = QByteArray()); void release(const QFontEngine::FaceId &face_id); // locks the struct for usage. Any read/write operations require locking. @@ -119,6 +122,7 @@ struct QFreetypeFace static void addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path, bool = false); private: + friend class QFontEngineFTRawFont; friend class QScopedPointerDeleter; QFreetypeFace() : _lock(QMutex::Recursive) {} ~QFreetypeFace() {} @@ -300,7 +304,10 @@ private: QFontEngineFT(const QFontDef &fd); virtual ~QFontEngineFT(); - bool init(FaceId faceId, bool antiaalias, GlyphFormat defaultFormat = Format_None); + bool init(FaceId faceId, bool antiaalias, GlyphFormat defaultFormat = Format_None, + const QByteArray &fontData = QByteArray()); + bool init(FaceId faceId, bool antialias, GlyphFormat format, + QFreetypeFace *freetypeFace); virtual HB_Error getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints); @@ -312,6 +319,7 @@ private: }; void setDefaultHintStyle(HintStyle style); + HintStyle defaultHintStyle() const { return default_hint_style; } protected: void freeGlyphSets(); @@ -335,6 +343,9 @@ protected: bool embeddedbitmap; private: + friend class QFontEngineFTRawFont; + + QFontEngineFT::Glyph *loadGlyphMetrics(QGlyphSet *set, uint glyph, GlyphFormat format) const; int loadFlags(QGlyphSet *set, GlyphFormat format, int flags, bool &hsubpixel, int &vfactor) const; GlyphFormat defaultFormat; diff --git a/src/gui/text/qfontengine_mac.mm b/src/gui/text/qfontengine_mac.mm index 7751bbe..673a7c8 100644 --- a/src/gui/text/qfontengine_mac.mm +++ b/src/gui/text/qfontengine_mac.mm @@ -922,27 +922,6 @@ static void addGlyphsToPathHelper(ATSUStyle style, glyph_t *glyphs, QFixedPoint DisposeATSCubicClosePathUPP(closePath); } -QFont QFontEngineMac::createExplicitFont() const -{ - FMFont fmFont = FMGetFontFromATSFontRef(fontID); - - FMFontFamily fmFamily; - FMFontStyle fmStyle; - QString familyName; - if (!FMGetFontFamilyInstanceFromFont(fmFont, &fmFamily, &fmStyle)) { - ATSFontFamilyRef familyRef = FMGetATSFontFamilyRefFromFontFamily(fmFamily); - QCFString cfFamilyName;; - ATSFontFamilyGetName(familyRef, kATSOptionFlagsDefault, &cfFamilyName); - familyName = cfFamilyName; - } else { - QCFString cfFontName; - ATSFontGetName(fontID, kATSOptionFlagsDefault, &cfFontName); - familyName = cfFontName; - } - - return createExplicitFontWithName(familyName); -} - void QFontEngineMac::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs, QPainterPath *path, QTextItem::RenderFlags) { diff --git a/src/gui/text/qfontengine_mac_p.h b/src/gui/text/qfontengine_mac_p.h index 6967348..385fa83 100644 --- a/src/gui/text/qfontengine_mac_p.h +++ b/src/gui/text/qfontengine_mac_p.h @@ -66,8 +66,6 @@ public: virtual qreal maxCharWidth() const; virtual QFixed averageCharWidth() const; - virtual QFont createExplicitFont() const; - virtual void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs, QPainterPath *path, QTextItem::RenderFlags); diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h index 7b29993..5b39fd3 100644 --- a/src/gui/text/qfontengine_p.h +++ b/src/gui/text/qfontengine_p.h @@ -185,9 +185,6 @@ public: virtual void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs, QPainterPath *path, QTextItem::RenderFlags flags); - /* Creates a QFont object to represent this particular QFontEngine */ - virtual QFont createExplicitFont() const; - void getGlyphPositions(const QGlyphLayout &glyphs, const QTransform &matrix, QTextItem::RenderFlags flags, QVarLengthArray &glyphs_out, QVarLengthArray &positions); @@ -276,7 +273,6 @@ public: int glyphFormat; protected: - QFont createExplicitFontWithName(const QString &familyName) const; static const QVector &grayPalette(); QFixed lastRightBearing(const QGlyphLayout &glyphs, bool round = false); @@ -431,6 +427,7 @@ public: protected: friend class QPSPrintEnginePrivate; friend class QPSPrintEngineFontMulti; + friend class QRawFont; virtual void loadEngine(int at) = 0; QVector engines; }; diff --git a/src/gui/text/qfontengine_x11_p.h b/src/gui/text/qfontengine_x11_p.h index 2a4a9cd..ad68fac 100644 --- a/src/gui/text/qfontengine_x11_p.h +++ b/src/gui/text/qfontengine_x11_p.h @@ -157,6 +157,7 @@ private: class Q_GUI_EXPORT QFontEngineX11FT : public QFontEngineFT { public: + explicit QFontEngineX11FT(const QFontDef &fontDef) : QFontEngineFT(fontDef) {} explicit QFontEngineX11FT(FcPattern *pattern, const QFontDef &fd, int screen); ~QFontEngineX11FT(); diff --git a/src/gui/text/qfontenginedirectwrite.cpp b/src/gui/text/qfontenginedirectwrite.cpp index af5bab2..f0a3644 100644 --- a/src/gui/text/qfontenginedirectwrite.cpp +++ b/src/gui/text/qfontenginedirectwrite.cpp @@ -170,17 +170,12 @@ namespace { } -QFontEngineDirectWrite::QFontEngineDirectWrite(const QString &name, - IDWriteFactory *directWriteFactory, - IDWriteGdiInterop *directWriteGdiInterop, - IDWriteFont *directWriteFont, +QFontEngineDirectWrite::QFontEngineDirectWrite(IDWriteFactory *directWriteFactory, + IDWriteFontFace *directWriteFontFace, qreal pixelSize) - : m_name(name) - , m_directWriteFont(directWriteFont) - , m_directWriteFontFace(0) + : m_directWriteFontFace(directWriteFontFace) , m_directWriteFactory(directWriteFactory) , m_directWriteBitmapRenderTarget(0) - , m_directWriteGdiInterop(directWriteGdiInterop) , m_lineThickness(-1) , m_unitsPerEm(-1) , m_ascent(-1) @@ -188,24 +183,17 @@ QFontEngineDirectWrite::QFontEngineDirectWrite(const QString &name, , m_xHeight(-1) , m_lineGap(-1) { - m_directWriteFont->AddRef(); m_directWriteFactory->AddRef(); - m_directWriteGdiInterop->AddRef(); + m_directWriteFontFace->AddRef(); fontDef.pixelSize = pixelSize; - - HRESULT hr = m_directWriteFont->CreateFontFace(&m_directWriteFontFace); - if (FAILED(hr)) - qErrnoWarning("QFontEngineDirectWrite: CreateFontFace failed"); - collectMetrics(); } QFontEngineDirectWrite::~QFontEngineDirectWrite() { - m_directWriteFont->Release(); m_directWriteFactory->Release(); - m_directWriteGdiInterop->Release(); + m_directWriteFontFace->Release(); if (m_directWriteBitmapRenderTarget != 0) m_directWriteBitmapRenderTarget->Release(); @@ -213,10 +201,10 @@ QFontEngineDirectWrite::~QFontEngineDirectWrite() void QFontEngineDirectWrite::collectMetrics() { - if (m_directWriteFont != 0) { + if (m_directWriteFontFace != 0) { DWRITE_FONT_METRICS metrics; - m_directWriteFont->GetMetrics(&metrics); + m_directWriteFontFace->GetMetrics(&metrics); m_unitsPerEm = metrics.designUnitsPerEm; m_lineThickness = DESIGN_TO_LOGICAL(metrics.underlineThickness); @@ -616,19 +604,25 @@ const char *QFontEngineDirectWrite::name() const bool QFontEngineDirectWrite::canRender(const QChar *string, int len) { - for (int i=0; iHasCharacter(codePoint, &exists); - if (FAILED(hr)) { - qErrnoWarning("QFontEngineDirectWrite::canRender: HasCharacter failed"); - return false; - } else if (!exists) { - return false; + QVarLengthArray codePoints(len); + int actualLength = 0; + for (int i=0; i glyphIndices(actualLength); + HRESULT hr = m_directWriteFontFace->GetGlyphIndices(codePoints.data(), actualLength, + glyphIndices.data()); + if (FAILED(hr)) { + qErrnoWarning(hr, "QFontEngineDirectWrite::canRender: GetGlyphIndices failed"); + return false; + } else { + for (int i=0; iglyphIndexes == other.d->glyphIndexes && d->glyphPositions == other.d->glyphPositions + && d->overline == other.d->overline + && d->underline == other.d->underline + && d->strikeOut == other.d->strikeOut && d->font == other.d->font)); } @@ -171,18 +184,17 @@ QGlyphs &QGlyphs::operator+=(const QGlyphs &other) \sa setFont() */ -QFont QGlyphs::font() const +QRawFont QGlyphs::font() const { return d->font; } /*! - Sets the font in which to look up the glyph indexes to \a font. This must be an explicitly - resolvable font which defines glyphs for the specified glyph indexes. + Sets the font in which to look up the glyph indexes to \a font. \sa font(), setGlyphIndexes() */ -void QGlyphs::setFont(const QFont &font) +void QGlyphs::setFont(const QRawFont &font) { detach(); d->font = font; @@ -234,7 +246,78 @@ void QGlyphs::clear() detach(); d->glyphPositions = QVector(); d->glyphIndexes = QVector(); - d->font = QFont(); + d->font = QRawFont(); + d->strikeOut = false; + d->overline = false; + d->underline = false; +} + +/*! + Returns true if this QGlyphs should be painted with an overline decoration. + + \sa setOverline() +*/ +bool QGlyphs::overline() const +{ + return d->overline; +} + +/*! + Indicates that this QGlyphs should be painted with an overline decoration if \a overline is true. + Otherwise the QGlyphs should be painted with no overline decoration. + + \sa overline() +*/ +void QGlyphs::setOverline(bool overline) +{ + detach(); + d->overline = overline; +} + +/*! + Returns true if this QGlyphs should be painted with an underline decoration. + + \sa setUnderline() +*/ +bool QGlyphs::underline() const +{ + return d->underline; +} + +/*! + Indicates that this QGlyphs should be painted with an underline decoration if \a underline is + true. Otherwise the QGlyphs should be painted with no underline decoration. + + \sa underline() +*/ +void QGlyphs::setUnderline(bool underline) +{ + detach(); + d->underline = underline; +} + +/*! + Returns true if this QGlyphs should be painted with a strike out decoration. + + \sa setStrikeOut() +*/ +bool QGlyphs::strikeOut() const +{ + return d->strikeOut; +} + +/*! + Indicates that this QGlyphs should be painted with an strike out decoration if \a strikeOut is + true. Otherwise the QGlyphs should be painted with no strike out decoration. + + \sa strikeOut() +*/ +void QGlyphs::setStrikeOut(bool strikeOut) +{ + detach(); + d->strikeOut = strikeOut; } QT_END_NAMESPACE + +#endif // QT_NO_RAWFONT diff --git a/src/gui/text/qglyphs.h b/src/gui/text/qglyphs.h index 5f37136..4d7dcaf 100644 --- a/src/gui/text/qglyphs.h +++ b/src/gui/text/qglyphs.h @@ -45,7 +45,9 @@ #include #include #include -#include +#include + +#if !defined(QT_NO_RAWFONT) QT_BEGIN_HEADER @@ -61,8 +63,8 @@ public: QGlyphs(const QGlyphs &other); ~QGlyphs(); - QFont font() const; - void setFont(const QFont &font); + QRawFont font() const; + void setFont(const QRawFont &font); QVector glyphIndexes() const; void setGlyphIndexes(const QVector &glyphIndexes); @@ -76,6 +78,15 @@ public: bool operator==(const QGlyphs &other) const; bool operator!=(const QGlyphs &other) const; + void setOverline(bool overline); + bool overline() const; + + void setUnderline(bool underline); + bool underline() const; + + void setStrikeOut(bool strikeOut); + bool strikeOut() const; + private: friend class QGlyphsPrivate; friend class QTextLine; @@ -85,12 +96,12 @@ private: void detach(); QExplicitlySharedDataPointer d; - }; QT_END_NAMESPACE QT_END_HEADER +#endif // QT_NO_RAWFONT #endif // QGLYPHS_H diff --git a/src/gui/text/qglyphs_p.h b/src/gui/text/qglyphs_p.h index c632e2f..944f777 100644 --- a/src/gui/text/qglyphs_p.h +++ b/src/gui/text/qglyphs_p.h @@ -53,8 +53,12 @@ // We mean it. // -#include #include "qglyphs.h" +#include "qrawfont.h" + +#include + +#if !defined(QT_NO_RAWFONT) QT_BEGIN_HEADER @@ -64,17 +68,30 @@ class QGlyphsPrivate: public QSharedData { public: QGlyphsPrivate() + : overline(false) + , underline(false) + , strikeOut(false) { } QGlyphsPrivate(const QGlyphsPrivate &other) - : QSharedData(other), glyphIndexes(other.glyphIndexes), glyphPositions(other.glyphPositions), font(other.font) + : QSharedData(other) + , glyphIndexes(other.glyphIndexes) + , glyphPositions(other.glyphPositions) + , font(other.font) + , overline(other.overline) + , underline(other.underline) + , strikeOut(other.strikeOut) { } QVector glyphIndexes; QVector glyphPositions; - QFont font; + QRawFont font; + + uint overline : 1; + uint underline : 1; + uint strikeOut : 1; }; QT_END_NAMESPACE @@ -82,3 +99,5 @@ QT_END_NAMESPACE QT_END_HEADER #endif // QGLYPHS_P_H + +#endif // QT_NO_RAWFONT diff --git a/src/gui/text/qrawfont.cpp b/src/gui/text/qrawfont.cpp new file mode 100644 index 0000000..4a715c2 --- /dev/null +++ b/src/gui/text/qrawfont.cpp @@ -0,0 +1,612 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui 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 "qglobal.h" + +#if !defined(QT_NO_RAWFONT) + +#include "qrawfont.h" +#include "qrawfont_p.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QRawFont + \brief The QRawFont class provides access to a single physical instance of a font. + \since 4.8 + + \ingroup text + \mainclass + + \note QRawFont is a low level class. For most purposes QFont is a more appropriate class. + + Most commonly, when presenting text in a user interface, the exact fonts used + to render the characters is to some extent unknown. This can be the case for several + reasons: For instance, the actual, physical fonts present on the target system could be + unexpected to the developers, or the text could contain user selected styles, sizes or + writing systems that are not supported by font chosen in the code. + + Therefore, Qt's QFont class really represents a query for fonts. When text is interpreted, + Qt will do its best to match the text to the query, but depending on the support, different + fonts can be used behind the scenes. + + For most use cases, this is both expected and necessary, as it minimizes the possibility of + text in the user interface being undisplayable. In some cases, however, more direct control + over the process might be useful. It is for these use cases the QRawFont class exists. + + A QRawFont object represents a single, physical instance of a given font in a given pixel size. + I.e. in the typical case it represents a set of TrueType or OpenType font tables and uses a + user specified pixel size to convert metrics into logical pixel units. In can be used in + combination with the QGlyphs class to draw specific glyph indexes at specific positions, and + also have accessors to some relevant data in the physical font. + + QRawFont only provides support for the main font technologies: GDI and DirectWrite on Windows + platforms, FreeType on Symbian and Linux platforms and CoreText on Mac OS X. For other + font back-ends, the APIs will be disabled. + + QRawFont can be constructed in a number of ways: + \list + \o \l It can be constructed by calling QTextLayout::glyphs() or QTextFragment::glyphs(). The + returned QGlyphs objects will contain QRawFont objects which represent the actual fonts + used to render each portion of the text. + \o \l It can be constructed by passing a QFont object to QRawFont::fromFont(). The function + will return a QRawFont object representing the font that will be selected as response to + the QFont query and the selected writing system. + \o \l It can be constructed by passing a file name or QByteArray directly to the QRawFont + constructor, or by calling loadFromFile() or loadFromData(). In this case, the + font will not be registered in QFontDatabase, and it will not be available as part of + regular font selection. + \endlist + + QRawFont is considered local to the thread in which it is constructed (either using a + constructor, or by calling loadFromData() or loadFromFile()). The QRawFont cannot be moved to a + different thread, but will have to be recreated in the thread in question. + + \note For the requirement of caching glyph indexes and font selections for static text to avoid + reshaping and relayouting in the inner loop of an application, a better choice is the QStaticText + class, since it optimizes the memory cost of the cache and also provides the possibility of paint + engine specific caches for an additional speed-up. +*/ + +/*! + \enum QRawFont::AntialiasingType + + This enum represents the different ways a glyph can be rasterized in the function + alphaMapForGlyph(). + + \value PixelAntialiasing Will rasterize by measuring the coverage of the shape on whole pixels. + The returned image contains the alpha values of each pixel based on the coverage of + the glyph shape. + \value SubPixelAntialiasing Will rasterize by measuring the coverage of each subpixel, + returning a separate alpha value for each of the red, green and blue components of + each pixel. +*/ + +/*! + Constructs an invalid QRawFont. +*/ +QRawFont::QRawFont() + : d(new QRawFontPrivate) +{ +} + +/*! + Constructs a QRawFont representing the font contained in the file referenced by \a fileName, + with \a pixelSize size in pixels, and the selected \a hintingPreference. + + \note The referenced file must contain a TrueType or OpenType font. +*/ +QRawFont::QRawFont(const QString &fileName, + int pixelSize, + QFont::HintingPreference hintingPreference) + : d(new QRawFontPrivate) +{ + loadFromFile(fileName, pixelSize, hintingPreference); +} + +/*! + Constructs a QRawFont representing the font contained in \a fontData. + + \note The data must contain a TrueType or OpenType font. +*/ +QRawFont::QRawFont(const QByteArray &fontData, + int pixelSize, + QFont::HintingPreference hintingPreference) + : d(new QRawFontPrivate) +{ + loadFromData(fontData, pixelSize, hintingPreference); +} + +/*! + Creates a QRawFont which is a copy of \a other. +*/ +QRawFont::QRawFont(const QRawFont &other) +{ + d = other.d; +} + +/*! + Destroys the QRawFont +*/ +QRawFont::~QRawFont() +{ +} + +/*! + Assigns \a other to this QRawFont. +*/ +QRawFont &QRawFont::operator=(const QRawFont &other) +{ + d = other.d; + return *this; +} + +/*! + Returns true if the QRawFont is valid and false otherwise. +*/ +bool QRawFont::isValid() const +{ + Q_ASSERT(d->thread == 0 || d->thread == QThread::currentThread()); + return d->fontEngine != 0; +} + +/*! + Replaces the current QRawFont with the contents of the file references by \a fileName. + + The file must reference a TrueType or OpenType font. + + \sa loadFromData() +*/ +void QRawFont::loadFromFile(const QString &fileName, + int pixelSize, + QFont::HintingPreference hintingPreference) +{ + QFile file(fileName); + if (file.open(QIODevice::ReadOnly)) + loadFromData(file.readAll(), pixelSize, hintingPreference); +} + +/*! + Replaces the current QRawFont with the contents of \a fontData. + + The \a fontData must contain a TrueType or OpenType font. + + \sa loadFromFile() +*/ +void QRawFont::loadFromData(const QByteArray &fontData, + int pixelSize, + QFont::HintingPreference hintingPreference) +{ + detach(); + d->cleanUp(); + d->hintingPreference = hintingPreference; + d->thread = QThread::currentThread(); + d->platformLoadFromData(fontData, pixelSize, hintingPreference); +} + +/*! + This function returns a rasterized image of the glyph at a given \a glyphIndex in the underlying + font, if the QRawFont is valid, otherwise it will return an invalid QImage. + + If \a antialiasingType is set to QRawFont::SubPixelAntialiasing, then the resulting image will be + in QImage::Format_RGB32 and the RGB values of each pixel will represent the subpixel opacities of + the pixel in the rasterization of the glyph. Otherwise, the image will be in the format of + QImage::Format_A8 and each pixel will contain the opacity of the pixel in the rasterization. + + \sa pathForGlyph(), QPainter::drawGlyphs() +*/ +QImage QRawFont::alphaMapForGlyph(quint32 glyphIndex, AntialiasingType antialiasingType, + const QTransform &transform) const +{ + if (!isValid()) + return QImage(); + + if (antialiasingType == SubPixelAntialiasing) + return d->fontEngine->alphaRGBMapForGlyph(glyphIndex, QFixed(), 0, transform); + else + return d->fontEngine->alphaMapForGlyph(glyphIndex, QFixed(), transform); +} + +/*! + This function returns the shape of the glyph at a given \a glyphIndex in the underlying font + if the QRawFont is valid. Otherwise, it returns an empty QPainterPath. + + The returned glyph will always be unhinted. + + \sa alphaMapForGlyph(), QPainterPath::addText() +*/ +QPainterPath QRawFont::pathForGlyph(quint32 glyphIndex) const +{ + if (!isValid()) + return QPainterPath(); + + QFixedPoint position; + QPainterPath path; + d->fontEngine->addGlyphsToPath(&glyphIndex, &position, 1, &path, 0); + return path; +} + +/*! + Returns true if this QRawFont is equal to \a other. Otherwise, returns false. +*/ +bool QRawFont::operator==(const QRawFont &other) const +{ + return d->fontEngine == other.d->fontEngine; +} + +/*! + Returns the ascent of this QRawFont in pixel units. + + \sa QFontMetricsF::ascent() +*/ +qreal QRawFont::ascent() const +{ + if (!isValid()) + return 0.0; + + return d->fontEngine->ascent().toReal(); +} + +/*! + Returns the descent of this QRawFont in pixel units. + + \sa QFontMetricsF::descent() +*/ +qreal QRawFont::descent() const +{ + if (!isValid()) + return 0.0; + + return d->fontEngine->descent().toReal(); +} + +/*! + Returns the pixel size set for this QRawFont. The pixel size affects how glyphs are + rasterized, the size of glyphs returned by pathForGlyph(), and is used to convert + internal metrics from design units to logical pixel units. + + \sa setPixelSize() +*/ +int QRawFont::pixelSize() const +{ + if (!isValid()) + return -1; + + return d->fontEngine->fontDef.pixelSize; +} + +/*! + Returns the number of design units define the width and height of the em square + for this QRawFont. This value is used together with the pixel size when converting design metrics + to pixel units, as the internal metrics are specified in design units and the pixel size gives + the size of 1 em in pixels. + + \sa pixelSize(), setPixelSize() +*/ +qreal QRawFont::unitsPerEm() const +{ + if (!isValid()) + return 0.0; + + return d->fontEngine->emSquareSize().toReal(); +} + +/*! + Returns the family name of this QRawFont. +*/ +QString QRawFont::familyName() const +{ + if (!isValid()) + return QString(); + + return d->fontEngine->fontDef.family; +} + +/*! + Returns the style of this QRawFont. + + \sa QFont::style() +*/ +QFont::Style QRawFont::style() const +{ + if (!isValid()) + return QFont::StyleNormal; + + return QFont::Style(d->fontEngine->fontDef.style); +} + +/*! + Returns the weight of this QRawFont. + + \sa QFont::weight() +*/ +int QRawFont::weight() const +{ + if (!isValid()) + return -1; + + return int(d->fontEngine->fontDef.weight); +} + +/*! + Converts a string of unicode points to glyph indexes using the CMAP table in the + underlying font. Note that in cases where there are other tables in the font that affect the + shaping of the text, the returned glyph indexes will not correctly represent the rendering + of the text. To get the correctly shaped text, you can use QTextLayout to lay out and shape the + text, and then call QTextLayout::glyphs() to get the set of glyph index list and QRawFont pairs. + + \sa advancesForGlyphIndexes(), QGlyphs, QTextLayout::glyphs(), QTextFragment::glyphs() +*/ +QVector QRawFont::glyphIndexesForString(const QString &text) const +{ + if (!isValid()) + return QVector(); + + int nglyphs = text.size(); + QVarLengthGlyphLayoutArray glyphs(nglyphs); + if (!d->fontEngine->stringToCMap(text.data(), text.size(), &glyphs, &nglyphs, + QTextEngine::GlyphIndicesOnly)) { + glyphs.resize(nglyphs); + if (!d->fontEngine->stringToCMap(text.data(), text.size(), &glyphs, &nglyphs, + QTextEngine::GlyphIndicesOnly)) { + Q_ASSERT_X(false, Q_FUNC_INFO, "stringToCMap shouldn't fail twice"); + return QVector(); + } + } + + QVector glyphIndexes; + for (int i=0; i QRawFont::advancesForGlyphIndexes(const QVector &glyphIndexes) const +{ + if (!isValid()) + return QVector(); + + int numGlyphs = glyphIndexes.size(); + QVarLengthGlyphLayoutArray glyphs(numGlyphs); + qMemCopy(glyphs.glyphs, glyphIndexes.data(), numGlyphs * sizeof(quint32)); + + d->fontEngine->recalcAdvances(&glyphs, 0); + + QVector advances; + for (int i=0; ihintingPreference; +} + +/*! + Retrieves the sfnt table named \a tagName from the underlying physical font, or an empty + byte array if no such table was found. The returned font table's byte order is Big Endian, like + the sfnt format specifies. The \a tagName must be four characters long and should be formatted + in the default endianness of the current platform. +*/ +QByteArray QRawFont::fontTable(const char *tagName) const +{ + if (!isValid()) + return QByteArray(); + + const quint32 *tagId = reinterpret_cast(tagName); + return d->fontEngine->getSfntTable(qToBigEndian(*tagId)); +} + +// From qfontdatabase.cpp +extern QList qt_determine_writing_systems_from_truetype_bits(quint32 unicodeRange[4], quint32 codePageRange[2]); + +/*! + Returns a list of writing systems supported by the font according to designer supplied + information in the font file. Please note that this does not guarantee support for a + specific unicode point in the font. You can use the supportsCharacter() to check support + for a single, specific character. + + \note The list is determined based on the unicode ranges and codepage ranges set in the font's + OS/2 table and requires such a table to be present in the underlying font file. + + \sa supportsCharacter() +*/ +QList QRawFont::supportedWritingSystems() const +{ + if (isValid()) { + QByteArray os2Table = fontTable("OS/2"); + if (!os2Table.isEmpty() && os2Table.size() > 86) { + char *data = os2Table.data(); + quint32 *bigEndianUnicodeRanges = reinterpret_cast(data + 42); + quint32 *bigEndianCodepageRanges = reinterpret_cast(data + 78); + + quint32 unicodeRanges[4]; + quint32 codepageRanges[2]; + + for (int i=0; i<4; ++i) { + if (i < 2) + codepageRanges[i] = qFromBigEndian(bigEndianCodepageRanges[i]); + unicodeRanges[i] = qFromBigEndian(bigEndianUnicodeRanges[i]); + } + + return qt_determine_writing_systems_from_truetype_bits(unicodeRanges, codepageRanges); + } + } + + return QList(); +} + +/*! + Returns true if the font has a glyph that corresponds to the given \a character. + + \sa supportedWritingSystems() +*/ +bool QRawFont::supportsCharacter(const QChar &character) const +{ + if (!isValid()) + return false; + + return d->fontEngine->canRender(&character, 1); +} + +/*! + Returns true if the font has a glyph that corresponds to the UCS-4 encoded character \a ucs4. + + \sa supportedWritingSystems() +*/ +bool QRawFont::supportsCharacter(quint32 ucs4) const +{ + if (!isValid()) + return false; + + QString str = QString::fromUcs4(&ucs4, 1); + return d->fontEngine->canRender(str.constData(), str.size()); +} + +// qfontdatabase.cpp +extern int qt_script_for_writing_system(QFontDatabase::WritingSystem writingSystem); + +/*! + Fetches the physical representation based on a \a font query. The physical font returned is + the font that will be preferred by Qt in order to display text in the selected \a writingSystem. +*/ +QRawFont QRawFont::fromFont(const QFont &font, QFontDatabase::WritingSystem writingSystem) +{ +#if defined(Q_WS_MAC) + QTextLayout layout(QFontDatabase::writingSystemSample(writingSystem), font); + layout.beginLayout(); + QTextLine line = layout.createLine(); + layout.endLayout(); + QList list = layout.glyphs(); + if (list.size()) { + // Pick the one matches the family name we originally requested, + // if none of them match, just pick the first one + for (int i = 0; i < list.size(); i++) { + QGlyphs glyphs = list.at(i); + QRawFont rawfont = glyphs.font(); + if (rawfont.familyName() == font.family()) + return rawfont; + } + return list.at(0).font(); + } + return QRawFont(); +#else + QFontPrivate *font_d = QFontPrivate::get(font); + int script = qt_script_for_writing_system(writingSystem); + QFontEngine *fe = font_d->engineForScript(script); + + if (fe != 0 && fe->type() == QFontEngine::Multi) { + QFontEngineMulti *multiEngine = static_cast(fe); + fe = multiEngine->engine(0); + if (fe == 0) { + multiEngine->loadEngine(0); + fe = multiEngine->engine(0); + } + } + + if (fe != 0) { + QRawFont rawFont; + rawFont.d.data()->fontEngine = fe; + rawFont.d.data()->fontEngine->ref.ref(); + rawFont.d.data()->hintingPreference = font.hintingPreference(); + return rawFont; + } else { + return QRawFont(); + } +#endif +} + +/*! + Sets the pixel size with which this font should be rendered to \a pixelSize. +*/ +void QRawFont::setPixelSize(int pixelSize) +{ + detach(); + d->platformSetPixelSize(pixelSize); +} + +/*! + \internal +*/ +void QRawFont::detach() +{ + if (d->ref != 1) + d.detach(); +} + +/*! + \internal +*/ +void QRawFontPrivate::cleanUp() +{ + platformCleanUp(); + if (fontEngine != 0) { + fontEngine->ref.deref(); + if (fontEngine->cache_count == 0 && fontEngine->ref == 0) + delete fontEngine; + fontEngine = 0; + } + hintingPreference = QFont::PreferDefaultHinting; +} + +#endif // QT_NO_RAWFONT + +QT_END_NAMESPACE diff --git a/src/gui/text/qrawfont.h b/src/gui/text/qrawfont.h new file mode 100644 index 0000000..96dc838 --- /dev/null +++ b/src/gui/text/qrawfont.h @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui 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$ +** +****************************************************************************/ + +#ifndef QRAWFONT_H +#define QRAWFONT_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(QT_NO_RAWFONT) + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QRawFontPrivate; +class Q_GUI_EXPORT QRawFont +{ +public: + enum AntialiasingType { + PixelAntialiasing, + SubPixelAntialiasing + }; + + QRawFont(); + QRawFont(const QString &fileName, + int pixelSize, + QFont::HintingPreference hintingPreference = QFont::PreferDefaultHinting); + QRawFont(const QByteArray &fontData, + int pixelSize, + QFont::HintingPreference hintingPreference = QFont::PreferDefaultHinting); + QRawFont(const QRawFont &other); + ~QRawFont(); + + bool isValid() const; + + QRawFont &operator=(const QRawFont &other); + bool operator==(const QRawFont &other) const; + + QString familyName() const; + + QFont::Style style() const; + int weight() const; + + QVector glyphIndexesForString(const QString &text) const; + QVector advancesForGlyphIndexes(const QVector &glyphIndexes) const; + + QImage alphaMapForGlyph(quint32 glyphIndex, + AntialiasingType antialiasingType = SubPixelAntialiasing, + const QTransform &transform = QTransform()) const; + QPainterPath pathForGlyph(quint32 glyphIndex) const; + + void setPixelSize(int pixelSize); + int pixelSize() const; + + QFont::HintingPreference hintingPreference() const; + + qreal ascent() const; + qreal descent() const; + + qreal unitsPerEm() const; + + void loadFromFile(const QString &fileName, + int pixelSize, + QFont::HintingPreference hintingPreference); + + void loadFromData(const QByteArray &fontData, + int pixelSize, + QFont::HintingPreference hintingPreference); + + bool supportsCharacter(quint32 ucs4) const; + bool supportsCharacter(const QChar &character) const; + QList supportedWritingSystems() const; + + QByteArray fontTable(const char *tagName) const; + + static QRawFont fromFont(const QFont &font, + QFontDatabase::WritingSystem writingSystem = QFontDatabase::Any); + +private: + friend class QRawFontPrivate; + + void detach(); + + QExplicitlySharedDataPointer d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QT_NO_RAWFONT + +#endif // QRAWFONT_H diff --git a/src/gui/text/qrawfont_ft.cpp b/src/gui/text/qrawfont_ft.cpp new file mode 100644 index 0000000..eefbd92 --- /dev/null +++ b/src/gui/text/qrawfont_ft.cpp @@ -0,0 +1,189 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui 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 + +#if !defined(QT_NO_RAWFONT) + +#include "qrawfont_p.h" +#include "qfontengine_ft_p.h" + +#if defined(Q_WS_X11) +# include "qfontengine_x11_p.h" +#endif + +QT_BEGIN_NAMESPACE + +class QFontEngineFTRawFont + +#if defined(Q_WS_X11) + : public QFontEngineX11FT +#else + : public QFontEngineFT +#endif + +{ +public: + QFontEngineFTRawFont(const QFontDef &fontDef) +#if defined(Q_WS_X11) + : QFontEngineX11FT(fontDef) +#else + : QFontEngineFT(fontDef) +#endif + { + } + + void updateFamilyNameAndStyle() + { + fontDef.family = QString::fromAscii(freetype->face->family_name); + + if (freetype->face->style_flags & FT_STYLE_FLAG_ITALIC) + fontDef.style = QFont::StyleItalic; + + if (freetype->face->style_flags & FT_STYLE_FLAG_BOLD) + fontDef.weight = QFont::Bold; + } + + bool initFromData(const QByteArray &fontData) + { + FaceId faceId; + faceId.filename = ""; + faceId.index = 0; + + return init(faceId, true, Format_None, fontData); + } + + bool initFromFontEngine(QFontEngine *oldFontEngine) + { + QFontEngineFT *fe = static_cast(oldFontEngine); + + // Increase the reference of this QFreetypeFace since one more QFontEngineFT + // will be using it + fe->freetype->ref.ref(); + if (!init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype)) + return false; + + default_load_flags = fe->default_load_flags; + default_hint_style = fe->default_hint_style; + antialias = fe->antialias; + transform = fe->transform; + embolden = fe->embolden; + subpixelType = fe->subpixelType; + lcdFilterType = fe->lcdFilterType; + canUploadGlyphsToServer = fe->canUploadGlyphsToServer; + embeddedbitmap = fe->embeddedbitmap; + +#if defined(Q_WS_X11) + xglyph_format = static_cast(fe)->xglyph_format; +#endif + return true; + } +}; + + +void QRawFontPrivate::platformCleanUp() +{ + // Font engine handles all resources +} + +void QRawFontPrivate::platformLoadFromData(const QByteArray &fontData, int pixelSize, + QFont::HintingPreference hintingPreference) +{ + Q_ASSERT(fontEngine == 0); + + QFontDef fontDef; + fontDef.pixelSize = pixelSize; + + QFontEngineFTRawFont *fe = new QFontEngineFTRawFont(fontDef); + if (!fe->initFromData(fontData)) { + delete fe; + return; + } + + fe->updateFamilyNameAndStyle(); + + switch (hintingPreference) { + case QFont::PreferNoHinting: + fe->setDefaultHintStyle(QFontEngineFT::HintNone); + break; + case QFont::PreferFullHinting: + fe->setDefaultHintStyle(QFontEngineFT::HintFull); + break; + case QFont::PreferVerticalHinting: + fe->setDefaultHintStyle(QFontEngineFT::HintLight); + break; + default: + // Leave it as it is + break; + } + + fontEngine = fe; + fontEngine->ref.ref(); +} + +void QRawFontPrivate::platformSetPixelSize(int pixelSize) +{ + if (fontEngine == NULL) + return; + + QFontEngine *oldFontEngine = fontEngine; + + QFontDef fontDef; + fontDef.pixelSize = pixelSize; + QFontEngineFTRawFont *fe = new QFontEngineFTRawFont(fontDef); + if (!fe->initFromFontEngine(oldFontEngine)) { + delete fe; + return; + } + + fontEngine = fe; + fontEngine->fontDef = oldFontEngine->fontDef; + fontEngine->fontDef.pixelSize = pixelSize; + fontEngine->ref.ref(); + Q_ASSERT(fontEngine != oldFontEngine); + oldFontEngine->ref.deref(); + if (oldFontEngine->cache_count == 0 && oldFontEngine->ref == 0) + delete oldFontEngine; +} + +QT_END_NAMESPACE + +#endif // QT_NO_RAWFONT diff --git a/src/gui/text/qrawfont_mac.cpp b/src/gui/text/qrawfont_mac.cpp new file mode 100644 index 0000000..56005c6 --- /dev/null +++ b/src/gui/text/qrawfont_mac.cpp @@ -0,0 +1,105 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite 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 + +#if !defined(QT_NO_RAWFONT) + +#include "qrawfont_p.h" +#include "qfontengine_coretext_p.h" + +QT_BEGIN_NAMESPACE + +void QRawFontPrivate::platformCleanUp() +{ +} + +extern int qt_defaultDpi(); + +void QRawFontPrivate::platformLoadFromData(const QByteArray &fontData, + int pixelSize, + QFont::HintingPreference hintingPreference) +{ + // Mac OS X ignores it + Q_UNUSED(hintingPreference); + + QCFType dataProvider = CGDataProviderCreateWithData(NULL, + fontData.constData(), fontData.size(), NULL); + + CGFontRef cgFont = CGFontCreateWithDataProvider(dataProvider); + + if (cgFont == NULL) { + qWarning("QRawFont::platformLoadFromData: CGFontCreateWithDataProvider failed"); + } else { + QFontDef def; + def.pixelSize = pixelSize; + def.pointSize = pixelSize * 72.0 / qt_defaultDpi(); + fontEngine = new QCoreTextFontEngine(cgFont, def); + CFRelease(cgFont); + fontEngine->ref.ref(); + } +} + +void QRawFontPrivate::platformSetPixelSize(int pixelSize) +{ + if (fontEngine == NULL) + return; + + QFontEngine *oldFontEngine = fontEngine; + + QFontDef fontDef = oldFontEngine->fontDef; + fontDef.pixelSize = pixelSize; + fontDef.pointSize = pixelSize * 72.0 / qt_defaultDpi(); + + QCoreTextFontEngine *ctFontEngine = static_cast(oldFontEngine); + Q_ASSERT(ctFontEngine->cgFont); + + fontEngine = new QCoreTextFontEngine(ctFontEngine->cgFont, fontDef); + fontEngine->ref.ref(); + Q_ASSERT(fontEngine != oldFontEngine); + oldFontEngine->ref.deref(); + if (oldFontEngine->cache_count == 0 && oldFontEngine->ref == 0) + delete oldFontEngine; +} + +QT_END_NAMESPACE + +#endif // QT_NO_RAWFONT diff --git a/src/gui/text/qrawfont_p.h b/src/gui/text/qrawfont_p.h new file mode 100644 index 0000000..f9a9ab5 --- /dev/null +++ b/src/gui/text/qrawfont_p.h @@ -0,0 +1,132 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui 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$ +** +****************************************************************************/ + +#ifndef QRAWFONTPRIVATE_P_H +#define QRAWFONTPRIVATE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qrawfont.h" +#include "qfontengine_p.h" +#include + +#if !defined(QT_NO_RAWFONT) + +QT_BEGIN_NAMESPACE + +namespace { class CustomFontFileLoader; } +class Q_AUTOTEST_EXPORT QRawFontPrivate +{ +public: + QRawFontPrivate() + : fontEngine(0) + , hintingPreference(QFont::PreferDefaultHinting) + , thread(0) +#if defined(Q_WS_WIN) + , fontHandle(NULL) + , ptrAddFontMemResourceEx(NULL) + , ptrRemoveFontMemResourceEx(NULL) +#endif + {} + + QRawFontPrivate(const QRawFontPrivate &other) + : hintingPreference(other.hintingPreference) + , thread(other.thread) +#if defined(Q_WS_WIN) + , fontHandle(NULL) + , ptrAddFontMemResourceEx(other.ptrAddFontMemResourceEx) + , ptrRemoveFontMemResourceEx(other.ptrRemoveFontMemResourceEx) + , uniqueFamilyName(other.uniqueFamilyName) +#endif + { + fontEngine = other.fontEngine; + if (fontEngine != 0) + fontEngine->ref.ref(); + } + + ~QRawFontPrivate() + { + Q_ASSERT(ref == 0); + cleanUp(); + } + + void cleanUp(); + void platformCleanUp(); + void platformLoadFromData(const QByteArray &fontData, + int pixelSize, + QFont::HintingPreference hintingPreference); + void platformSetPixelSize(int pixelSize); + + static QRawFontPrivate *get(const QRawFont &font) { return font.d.data(); } + + QFontEngine *fontEngine; + QFont::HintingPreference hintingPreference; + QThread *thread; + QAtomicInt ref; + +#if defined(Q_WS_WIN) + HANDLE fontHandle; + + typedef HANDLE (WINAPI *PtrAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *); + typedef BOOL (WINAPI *PtrRemoveFontMemResourceEx)(HANDLE); + + PtrAddFontMemResourceEx ptrAddFontMemResourceEx; + PtrRemoveFontMemResourceEx ptrRemoveFontMemResourceEx; + + QString uniqueFamilyName; + +#endif // Q_WS_WIN +}; + +QT_END_NAMESPACE + +#endif // QT_NO_RAWFONT + +#endif // QRAWFONTPRIVATE_P_H diff --git a/src/gui/text/qrawfont_win.cpp b/src/gui/text/qrawfont_win.cpp new file mode 100644 index 0000000..fb5c6f4 --- /dev/null +++ b/src/gui/text/qrawfont_win.cpp @@ -0,0 +1,750 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite 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 "qrawfont_p.h" +#include + +#if !defined(QT_NO_DIRECTWRITE) +# include "qfontenginedirectwrite_p.h" +# include +#endif + +#if !defined(QT_NO_RAWFONT) + +QT_BEGIN_NAMESPACE + +namespace { + + template + struct BigEndian + { + quint8 data[sizeof(T)]; + + operator T() const + { + T littleEndian = 0; + for (int i=0; i &operator=(const T &t) + { + for (int i=0; i> (sizeof(T) - i - 1) * 8) & 0xff); + } + + return *this; + } + }; + +# pragma pack(1) + + // Common structure for all formats of the "name" table + struct NameTable + { + BigEndian format; + BigEndian count; + BigEndian stringOffset; + }; + + struct NameRecord + { + BigEndian platformID; + BigEndian encodingID; + BigEndian languageID; + BigEndian nameID; + BigEndian length; + BigEndian offset; + }; + + struct OffsetSubTable + { + BigEndian scalerType; + BigEndian numTables; + BigEndian searchRange; + BigEndian entrySelector; + BigEndian rangeShift; + }; + + struct TableDirectory + { + BigEndian identifier; + BigEndian checkSum; + BigEndian offset; + BigEndian length; + }; + + struct OS2Table + { + BigEndian version; + BigEndian avgCharWidth; + BigEndian weightClass; + BigEndian widthClass; + BigEndian type; + BigEndian subscriptXSize; + BigEndian subscriptYSize; + BigEndian subscriptXOffset; + BigEndian subscriptYOffset; + BigEndian superscriptXSize; + BigEndian superscriptYSize; + BigEndian superscriptXOffset; + BigEndian superscriptYOffset; + BigEndian strikeOutSize; + BigEndian strikeOutPosition; + BigEndian familyClass; + quint8 panose[10]; + BigEndian unicodeRanges[4]; + quint8 vendorID[4]; + BigEndian selection; + BigEndian firstCharIndex; + BigEndian lastCharIndex; + BigEndian typoAscender; + BigEndian typoDescender; + BigEndian typoLineGap; + BigEndian winAscent; + BigEndian winDescent; + BigEndian codepageRanges[2]; + BigEndian height; + BigEndian capHeight; + BigEndian defaultChar; + BigEndian breakChar; + BigEndian maxContext; + }; + +# pragma pack() + + class EmbeddedFont + { + public: + EmbeddedFont(const QByteArray &fontData); + + QString changeFamilyName(const QString &newFamilyName); + QByteArray data() const { return m_fontData; } + TableDirectory *tableDirectoryEntry(const QByteArray &tagName); + QString familyName(TableDirectory *nameTableDirectory = 0); + + private: + QByteArray m_fontData; + }; + + EmbeddedFont::EmbeddedFont(const QByteArray &fontData) : m_fontData(fontData) + { + } + + TableDirectory *EmbeddedFont::tableDirectoryEntry(const QByteArray &tagName) + { + Q_ASSERT(tagName.size() == 4); + + const BigEndian *tagIdPtr = + reinterpret_cast *>(tagName.constData()); + quint32 tagId = *tagIdPtr; + + OffsetSubTable *offsetSubTable = reinterpret_cast(m_fontData.data()); + TableDirectory *tableDirectory = reinterpret_cast(offsetSubTable + 1); + + TableDirectory *nameTableDirectoryEntry = 0; + for (int i=0; inumTables; ++i, ++tableDirectory) { + if (tableDirectory->identifier == tagId) { + nameTableDirectoryEntry = tableDirectory; + break; + } + } + + return nameTableDirectoryEntry; + } + + QString EmbeddedFont::familyName(TableDirectory *nameTableDirectoryEntry) + { + QString name; + + if (nameTableDirectoryEntry == 0) + nameTableDirectoryEntry = tableDirectoryEntry("name"); + + if (nameTableDirectoryEntry != 0) { + NameTable *nameTable = reinterpret_cast(m_fontData.data() + + nameTableDirectoryEntry->offset); + NameRecord *nameRecord = reinterpret_cast(nameTable + 1); + for (int i=0; icount; ++i, ++nameRecord) { + if (nameRecord->nameID == 1 + && nameRecord->platformID == 3 // Windows + && nameRecord->languageID == 0x0409) { // US English + const void *ptr = reinterpret_cast(nameTable) + + nameTable->stringOffset + + nameRecord->offset; + + const BigEndian *s = reinterpret_cast *>(ptr); + for (int j=0; jlength / sizeof(quint16); ++j) + name += QChar(s[j]); + + break; + } + } + } + + return name; + } + + QString EmbeddedFont::changeFamilyName(const QString &newFamilyName) + { + TableDirectory *nameTableDirectoryEntry = tableDirectoryEntry("name"); + if (nameTableDirectoryEntry == 0) + return QString(); + + QString oldFamilyName = familyName(nameTableDirectoryEntry); + + // Reserve size for name table header, five required name records and string + const int requiredRecordCount = 5; + quint16 nameIds[requiredRecordCount] = { 1, 2, 3, 4, 6 }; + + int sizeOfHeader = sizeof(NameTable) + sizeof(NameRecord) * requiredRecordCount; + int newFamilyNameSize = newFamilyName.size() * sizeof(quint16); + + const QString regularString = QString::fromLatin1("Regular"); + int regularStringSize = regularString.size() * sizeof(quint16); + + // Align table size of table to 32 bits (pad with 0) + int fullSize = ((sizeOfHeader + newFamilyNameSize + regularStringSize) & ~3) + 4; + + QByteArray newNameTable(fullSize, char(0)); + + { + NameTable *nameTable = reinterpret_cast(newNameTable.data()); + nameTable->count = requiredRecordCount; + nameTable->stringOffset = sizeOfHeader; + + NameRecord *nameRecord = reinterpret_cast(nameTable + 1); + for (int i=0; inameID = nameIds[i]; + nameRecord->encodingID = 1; + nameRecord->languageID = 0x0409; + nameRecord->platformID = 3; + nameRecord->length = newFamilyNameSize; + + // Special case for sub-family + if (nameIds[i] == 4) { + nameRecord->offset = newFamilyNameSize; + nameRecord->length = regularStringSize; + } + } + + // nameRecord now points to string data + BigEndian *stringStorage = reinterpret_cast *>(nameRecord); + const quint16 *sourceString = newFamilyName.utf16(); + for (int i=0; i(newNameTable.data()); + quint32 *tableEnd = reinterpret_cast(newNameTable.data() + fullSize); + + quint32 checkSum = 0; + while (p < tableEnd) + checkSum += *(p++); + + nameTableDirectoryEntry->checkSum = checkSum; + nameTableDirectoryEntry->offset = m_fontData.size(); + nameTableDirectoryEntry->length = fullSize; + + m_fontData.append(newNameTable); + + return oldFamilyName; + } + +#if !defined(QT_NO_DIRECTWRITE) + + class DirectWriteFontFileStream: public IDWriteFontFileStream + { + public: + DirectWriteFontFileStream(const QByteArray &fontData) + : m_fontData(fontData) + , m_referenceCount(0) + { + } + + ~DirectWriteFontFileStream() + { + } + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + HRESULT STDMETHODCALLTYPE ReadFileFragment(const void **fragmentStart, UINT64 fileOffset, + UINT64 fragmentSize, OUT void **fragmentContext); + void STDMETHODCALLTYPE ReleaseFileFragment(void *fragmentContext); + HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64 *fileSize); + HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64 *lastWriteTime); + + private: + QByteArray m_fontData; + ULONG m_referenceCount; + }; + + HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::QueryInterface(REFIID iid, void **object) + { + if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) { + *object = this; + AddRef(); + return S_OK; + } else { + *object = NULL; + return E_NOINTERFACE; + } + } + + ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::AddRef() + { + return InterlockedIncrement(&m_referenceCount); + } + + ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::Release() + { + ULONG newCount = InterlockedDecrement(&m_referenceCount); + if (newCount == 0) + delete this; + return newCount; + } + + HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::ReadFileFragment( + const void **fragmentStart, + UINT64 fileOffset, + UINT64 fragmentSize, + OUT void **fragmentContext) + { + *fragmentContext = NULL; + if (fragmentSize + fileOffset <= m_fontData.size()) { + *fragmentStart = m_fontData.data() + fileOffset; + return S_OK; + } else { + *fragmentStart = NULL; + return E_FAIL; + } + } + + void STDMETHODCALLTYPE DirectWriteFontFileStream::ReleaseFileFragment(void *) + { + } + + HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetFileSize(UINT64 *fileSize) + { + *fileSize = m_fontData.size(); + return S_OK; + } + + HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetLastWriteTime(UINT64 *lastWriteTime) + { + *lastWriteTime = 0; + return E_NOTIMPL; + } + + class DirectWriteFontFileLoader: public IDWriteFontFileLoader + { + public: + DirectWriteFontFileLoader() : m_referenceCount(0) {} + + ~DirectWriteFontFileLoader() + { + } + + inline void addKey(const void *key, const QByteArray &fontData) + { + Q_ASSERT(!m_fontDatas.contains(key)); + m_fontDatas.insert(key, fontData); + } + + inline void removeKey(const void *key) + { + m_fontDatas.remove(key); + } + + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object); + ULONG STDMETHODCALLTYPE AddRef(); + ULONG STDMETHODCALLTYPE Release(); + + HRESULT STDMETHODCALLTYPE CreateStreamFromKey(void const *fontFileReferenceKey, + UINT32 fontFileReferenceKeySize, + OUT IDWriteFontFileStream **fontFileStream); + + private: + ULONG m_referenceCount; + QHash m_fontDatas; + }; + + HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::QueryInterface(const IID &iid, + void **object) + { + if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileLoader)) { + *object = this; + AddRef(); + return S_OK; + } else { + *object = NULL; + return E_NOINTERFACE; + } + } + + ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::AddRef() + { + return InterlockedIncrement(&m_referenceCount); + } + + ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::Release() + { + ULONG newCount = InterlockedDecrement(&m_referenceCount); + if (newCount == 0) + delete this; + return newCount; + } + + HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::CreateStreamFromKey( + void const *fontFileReferenceKey, + UINT32 fontFileReferenceKeySize, + IDWriteFontFileStream **fontFileStream) + { + Q_UNUSED(fontFileReferenceKeySize); + + if (fontFileReferenceKeySize != sizeof(const void *)) { + qWarning("DirectWriteFontFileLoader::CreateStreamFromKey: Wrong key size"); + return E_FAIL; + } + + const void *key = *reinterpret_cast(fontFileReferenceKey); + *fontFileStream = NULL; + if (!m_fontDatas.contains(key)) + return E_FAIL; + + QByteArray fontData = m_fontDatas.value(key); + DirectWriteFontFileStream *stream = new DirectWriteFontFileStream(fontData); + stream->AddRef(); + *fontFileStream = stream; + + return S_OK; + } + + class CustomFontFileLoader + { + public: + CustomFontFileLoader() : m_directWriteFactory(0), m_directWriteFontFileLoader(0) + { + HRESULT hres = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, + __uuidof(IDWriteFactory), + reinterpret_cast(&m_directWriteFactory)); + if (FAILED(hres)) { + qErrnoWarning(hres, "CustomFontFileLoader::CustomFontFileLoader: " + "DWriteCreateFactory failed."); + } else { + m_directWriteFontFileLoader = new DirectWriteFontFileLoader(); + m_directWriteFactory->RegisterFontFileLoader(m_directWriteFontFileLoader); + } + } + + ~CustomFontFileLoader() + { + if (m_directWriteFactory != 0 && m_directWriteFontFileLoader != 0) + m_directWriteFactory->UnregisterFontFileLoader(m_directWriteFontFileLoader); + + if (m_directWriteFactory != 0) + m_directWriteFactory->Release(); + } + + void addKey(const void *key, const QByteArray &fontData) + { + if (m_directWriteFontFileLoader != 0) + m_directWriteFontFileLoader->addKey(key, fontData); + } + + void removeKey(const void *key) + { + if (m_directWriteFontFileLoader != 0) + m_directWriteFontFileLoader->removeKey(key); + } + + IDWriteFontFileLoader *loader() const + { + return m_directWriteFontFileLoader; + } + + private: + IDWriteFactory *m_directWriteFactory; + DirectWriteFontFileLoader *m_directWriteFontFileLoader; + }; + +#endif + +} // Anonymous namespace + + +// From qfontdatabase_win.cpp +extern QFontEngine *qt_load_font_engine_win(const QFontDef &request); +// From qfontdatabase.cpp +extern QFont::Weight weightFromInteger(int weight); + +void QRawFontPrivate::platformCleanUp() +{ + if (fontHandle != NULL) { + if (ptrRemoveFontMemResourceEx == NULL) { + void *func = QSystemLibrary::resolve(QLatin1String("gdi32"), "RemoveFontMemResourceEx"); + ptrRemoveFontMemResourceEx = + reinterpret_cast(func); + } + + if (ptrRemoveFontMemResourceEx == NULL) { + qWarning("QRawFont::platformCleanUp: Can't find RemoveFontMemResourceEx in gdi32"); + fontHandle = NULL; + } else { + ptrRemoveFontMemResourceEx(fontHandle); + fontHandle = NULL; + } + } +} + +void QRawFontPrivate::platformLoadFromData(const QByteArray &_fontData, + int pixelSize, + QFont::HintingPreference hintingPreference) +{ + QByteArray fontData(_fontData); + EmbeddedFont font(fontData); + +#if !defined(QT_NO_DIRECTWRITE) + if (hintingPreference == QFont::PreferDefaultHinting + || hintingPreference == QFont::PreferFullHinting) +#endif + { + GUID guid; + CoCreateGuid(&guid); + + uniqueFamilyName = QString::fromLatin1("f") + + QString::number(guid.Data1, 36) + QLatin1Char('-') + + QString::number(guid.Data2, 36) + QLatin1Char('-') + + QString::number(guid.Data3, 36) + QLatin1Char('-') + + QString::number(*reinterpret_cast(guid.Data4), 36); + + QString actualFontName = font.changeFamilyName(uniqueFamilyName); + if (actualFontName.isEmpty()) { + qWarning("QRawFont::platformLoadFromData: Can't change family name of font"); + return; + } + + if (ptrAddFontMemResourceEx == NULL || ptrRemoveFontMemResourceEx == NULL) { + void *func = QSystemLibrary::resolve(QLatin1String("gdi32"), "RemoveFontMemResourceEx"); + ptrRemoveFontMemResourceEx = + reinterpret_cast(func); + + func = QSystemLibrary::resolve(QLatin1String("gdi32"), "AddFontMemResourceEx"); + ptrAddFontMemResourceEx = + reinterpret_cast(func); + } + + Q_ASSERT(fontHandle == NULL); + if (ptrAddFontMemResourceEx != NULL && ptrRemoveFontMemResourceEx != NULL) { + DWORD count = 0; + fontData = font.data(); + fontHandle = ptrAddFontMemResourceEx(fontData.data(), fontData.size(), 0, &count); + + if (count == 0 && fontHandle != NULL) { + ptrRemoveFontMemResourceEx(fontHandle); + fontHandle = NULL; + } + } + + if (fontHandle == NULL) { + qWarning("QRawFont::platformLoadFromData: AddFontMemResourceEx failed"); + } else { + QFontDef request; + request.family = uniqueFamilyName; + request.pixelSize = pixelSize; + request.styleStrategy = QFont::NoFontMerging | QFont::PreferMatch; + request.hintingPreference = hintingPreference; + + fontEngine = qt_load_font_engine_win(request); + if (request.family != fontEngine->fontDef.family) { + qWarning("QRawFont::platformLoadFromData: Failed to load font. " + "Got fallback instead: %s", qPrintable(fontEngine->fontDef.family)); + if (fontEngine->cache_count == 0 && fontEngine->ref == 0) + delete fontEngine; + fontEngine = 0; + } else { + Q_ASSERT(fontEngine->cache_count == 0 && fontEngine->ref == 0); + + // Override the generated font name + fontEngine->fontDef.family = actualFontName; + fontEngine->ref.ref(); + } + } + } +#if !defined(QT_NO_DIRECTWRITE) + else { + CustomFontFileLoader fontFileLoader; + fontFileLoader.addKey(this, fontData); + + IDWriteFactory *factory = NULL; + HRESULT hres = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, + __uuidof(IDWriteFactory), + reinterpret_cast(&factory)); + if (FAILED(hres)) { + qErrnoWarning(hres, "QRawFont::platformLoadFromData: DWriteCreateFactory failed"); + return; + } + + IDWriteFontFile *fontFile = NULL; + void *key = this; + + hres = factory->CreateCustomFontFileReference(&key, sizeof(void *), + fontFileLoader.loader(), &fontFile); + if (FAILED(hres)) { + qErrnoWarning(hres, "QRawFont::platformLoadFromData: " + "CreateCustomFontFileReference failed"); + factory->Release(); + return; + } + + BOOL isSupportedFontType; + DWRITE_FONT_FILE_TYPE fontFileType; + DWRITE_FONT_FACE_TYPE fontFaceType; + UINT32 numberOfFaces; + fontFile->Analyze(&isSupportedFontType, &fontFileType, &fontFaceType, &numberOfFaces); + if (!isSupportedFontType) { + fontFile->Release(); + factory->Release(); + return; + } + + IDWriteFontFace *directWriteFontFace = NULL; + hres = factory->CreateFontFace(fontFaceType, 1, &fontFile, 0, DWRITE_FONT_SIMULATIONS_NONE, + &directWriteFontFace); + if (FAILED(hres)) { + qErrnoWarning(hres, "QRawFont::platformLoadFromData: CreateFontFace failed"); + fontFile->Release(); + factory->Release(); + return; + } + + fontFile->Release(); + + fontEngine = new QFontEngineDirectWrite(factory, directWriteFontFace, pixelSize); + + // Get font family from font data + fontEngine->fontDef.family = font.familyName(); + fontEngine->ref.ref(); + + directWriteFontFace->Release(); + factory->Release(); + } +#endif + + // Get style and weight info + if (fontEngine != 0) { + TableDirectory *os2TableEntry = font.tableDirectoryEntry("OS/2"); + if (os2TableEntry != 0) { + const OS2Table *os2Table = + reinterpret_cast(fontData.constData() + + os2TableEntry->offset); + + bool italic = os2Table->selection & 1; + bool oblique = os2Table->selection & 128; + + if (italic) + fontEngine->fontDef.style = QFont::StyleItalic; + else if (oblique) + fontEngine->fontDef.style = QFont::StyleOblique; + else + fontEngine->fontDef.style = QFont::StyleNormal; + + fontEngine->fontDef.weight = weightFromInteger(os2Table->weightClass); + } + } +} + +void QRawFontPrivate::platformSetPixelSize(int pixelSize) +{ + if (fontEngine == NULL) + return; + + QFontEngine *oldFontEngine = fontEngine; + +#if !defined(QT_NO_DIRECTWRITE) + if (fontEngine->type() == QFontEngine::Win) +#endif + + { + QFontDef request = fontEngine->fontDef; + QString actualFontName = request.family; + if (!uniqueFamilyName.isEmpty()) + request.family = uniqueFamilyName; + request.pixelSize = pixelSize; + + fontEngine = qt_load_font_engine_win(request); + if (fontEngine != NULL) { + fontEngine->fontDef.family = actualFontName; + fontEngine->ref.ref(); + } + } + +#if !defined(QT_NO_DIRECTWRITE) + else { + QFontEngineDirectWrite *dWriteFE = static_cast(fontEngine); + fontEngine = new QFontEngineDirectWrite(dWriteFE->m_directWriteFactory, + dWriteFE->m_directWriteFontFace, + pixelSize); + + fontEngine->fontDef = dWriteFE->fontDef; + fontEngine->fontDef.pixelSize = pixelSize; + fontEngine->ref.ref(); + } +#endif + + Q_ASSERT(fontEngine != oldFontEngine); + oldFontEngine->ref.deref(); + if (oldFontEngine->cache_count == 0 && oldFontEngine->ref == 0) + delete oldFontEngine; +} + +QT_END_NAMESPACE + +#endif // QT_NO_RAWFONT diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index afe6949..93f71d3 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -54,12 +54,18 @@ #include "qpainterpath.h" #include "qglyphs.h" #include "qglyphs_p.h" +#include "qrawfont.h" +#include "qrawfont_p.h" #include #include #include "qfontengine_p.h" +#if !defined(QT_NO_FREETYPE) +# include "qfontengine_ft_p.h" +#endif + QT_BEGIN_NAMESPACE #define ObjectSelectionBrush (QTextFormat::ForegroundBrush + 1) @@ -1158,6 +1164,7 @@ static inline QRectF clipIfValid(const QRectF &rect, const QRectF &clip) \sa draw(), QPainter::drawGlyphs() */ +#if !defined(QT_NO_RAWFONT) QList QTextLayout::glyphs() const { QList glyphs; @@ -1166,6 +1173,7 @@ QList QTextLayout::glyphs() const return glyphs; } +#endif // QT_NO_RAWFONT /*! Draws the whole layout on the painter \a p at the position specified by \a pos. @@ -2257,6 +2265,7 @@ namespace { \sa QTextLayout::glyphs() */ +#if !defined(QT_NO_RAWFONT) QList QTextLine::glyphs(int from, int length) const { const QScriptLine &line = eng->lines[i]; @@ -2331,7 +2340,35 @@ QList QTextLine::glyphs(int from, int length) const QFontEngine *fontEngine = keys.at(i); // Make a font for this particular engine - QFont font = fontEngine->createExplicitFont(); + QRawFont font; + QRawFontPrivate *fontD = QRawFontPrivate::get(font); + fontD->fontEngine = fontEngine; + fontD->fontEngine->ref.ref(); + +#if defined(Q_WS_WIN) + if (fontEngine->supportsSubPixelPositions()) + fontD->hintingPreference = QFont::PreferVerticalHinting; + else + fontD->hintingPreference = QFont::PreferFullHinting; +#elif defined(Q_WS_MAC) + fontD->hintingPreference = QFont::PreferNoHinting; +#elif !defined(QT_NO_FREETYPE) + if (fontEngine->type() == QFontEngine::Freetype) { + QFontEngineFT *freeTypeEngine = static_cast(fontEngine); + switch (freeTypeEngine->defaultHintStyle()) { + case QFontEngineFT::HintNone: + fontD->hintingPreference = QFont::PreferNoHinting; + break; + case QFontEngineFT::HintLight: + fontD->hintingPreference = QFont::PreferVerticalHinting; + break; + case QFontEngineFT::HintMedium: + case QFontEngineFT::HintFull: + fontD->hintingPreference = QFont::PreferFullHinting; + break; + }; + } +#endif QList glyphLayouts = glyphLayoutHash.values(fontEngine); for (int j=0; j QTextLine::glyphs(int from, int length) const const QGlyphLayout &glyphLayout = glyphLayouts.at(j).glyphLayout; const QTextItem::RenderFlags &flags = glyphLayouts.at(j).flags; - font.setOverline(flags.testFlag(QTextItem::Overline)); - font.setUnderline(flags.testFlag(QTextItem::Underline)); - font.setStrikeOut(flags.testFlag(QTextItem::StrikeOut)); - QVarLengthArray glyphsArray; QVarLengthArray positionsArray; @@ -2361,19 +2394,22 @@ QList QTextLine::glyphs(int from, int length) const glyphIndexes.setGlyphIndexes(glyphs); glyphIndexes.setPositions(positions); - QPair key(fontEngine, int(flags)); + glyphIndexes.setOverline(flags.testFlag(QTextItem::Overline)); + glyphIndexes.setUnderline(flags.testFlag(QTextItem::Underline)); + glyphIndexes.setStrikeOut(flags.testFlag(QTextItem::StrikeOut)); + glyphIndexes.setFont(font); + QPair key(fontEngine, int(flags)); if (!glyphsHash.contains(key)) - glyphsHash.insert(key, QGlyphs()); - - QGlyphs &target = glyphsHash[key]; - target += glyphIndexes; - target.setFont(font); + glyphsHash.insert(key, glyphIndexes); + else + glyphsHash[key] += glyphIndexes; } } return glyphsHash.values(); } +#endif // QT_NO_RAWFONT /*! \fn void QTextLine::draw(QPainter *painter, const QPointF &position, const QTextLayout::FormatRange *selection) const diff --git a/src/gui/text/qtextlayout.h b/src/gui/text/qtextlayout.h index 0f64c33..9dd8ebd 100644 --- a/src/gui/text/qtextlayout.h +++ b/src/gui/text/qtextlayout.h @@ -167,7 +167,9 @@ public: qreal minimumWidth() const; qreal maximumWidth() const; +#if !defined(QT_NO_RAWFONT) QList glyphs() const; +#endif QTextEngine *engine() const { return d; } void setFlags(int flags); @@ -239,7 +241,10 @@ public: private: QTextLine(int line, QTextEngine *e) : i(line), eng(e) {} void layout_helper(int numGlyphs); + +#if !defined(QT_NO_RAWFONT) QList glyphs(int from, int length) const; +#endif friend class QTextLayout; friend class QTextFragment; diff --git a/src/gui/text/qtextobject.cpp b/src/gui/text/qtextobject.cpp index 0081550..0a9dff8 100644 --- a/src/gui/text/qtextobject.cpp +++ b/src/gui/text/qtextobject.cpp @@ -1661,6 +1661,7 @@ QTextBlock::iterator &QTextBlock::iterator::operator--() \sa QGlyphs, QTextBlock::layout(), QTextLayout::position(), QPainter::drawGlyphs() */ +#if !defined(QT_NO_RAWFONT) QList QTextFragment::glyphs() const { if (!p || !n) @@ -1684,6 +1685,7 @@ QList QTextFragment::glyphs() const return ret; } +#endif // QT_NO_RAWFONT /*! Returns the position of this text fragment in the document. diff --git a/src/gui/text/qtextobject.h b/src/gui/text/qtextobject.h index fface3f..2e588c2 100644 --- a/src/gui/text/qtextobject.h +++ b/src/gui/text/qtextobject.h @@ -316,7 +316,9 @@ public: int charFormatIndex() const; QString text() const; +#if !defined(QT_NO_RAWFONT) QList glyphs() const; +#endif private: const QTextDocumentPrivate *p; diff --git a/src/gui/text/text.pri b/src/gui/text/text.pri index 7fb2783..df9398c 100644 --- a/src/gui/text/text.pri +++ b/src/gui/text/text.pri @@ -41,7 +41,9 @@ HEADERS += \ text/qstatictext_p.h \ text/qstatictext.h \ text/qglyphs.h \ - text/qglyphs_p.h + text/qglyphs_p.h \ + text/qrawfont.h \ + text/qrawfont_p.h SOURCES += \ text/qfont.cpp \ @@ -72,12 +74,14 @@ SOURCES += \ text/qzip.cpp \ text/qtextodfwriter.cpp \ text/qstatictext.cpp \ - text/qglyphs.cpp + text/qglyphs.cpp \ + text/qrawfont.cpp win32 { SOURCES += \ text/qfont_win.cpp \ - text/qfontengine_win.cpp + text/qfontengine_win.cpp \ + text/qrawfont_win.cpp HEADERS += text/qfontengine_win_p.h } @@ -95,7 +99,8 @@ unix:x11 { SOURCES += \ text/qfont_x11.cpp \ text/qfontengine_x11.cpp \ - text/qfontengine_ft.cpp + text/qfontengine_ft.cpp \ + text/qrawfont_ft.cpp } !embedded:!qpa:!x11:mac { @@ -104,7 +109,8 @@ unix:x11 { OBJECTIVE_HEADERS += \ text/qfontengine_coretext_p.h SOURCES += \ - text/qfont_mac.cpp + text/qfont_mac.cpp \ + text/qrawfont_mac.cpp OBJECTIVE_SOURCES += \ text/qfontengine_coretext.mm \ text/qfontengine_mac.mm @@ -116,7 +122,8 @@ embedded { text/qfontengine_qws.cpp \ text/qfontengine_ft.cpp \ text/qfontengine_qpf.cpp \ - text/qabstractfontengine_qws.cpp + text/qabstractfontengine_qws.cpp \ + text/qrawfont_ft.cpp HEADERS += \ text/qfontengine_ft_p.h \ text/qfontengine_qpf_p.h \ @@ -143,7 +150,8 @@ symbian { text/qfont_s60.cpp contains(QT_CONFIG, freetype) { SOURCES += \ - text/qfontengine_ft.cpp + text/qfontengine_ft.cpp \ + text/qrawfont_ft.cpp HEADERS += \ text/qfontengine_ft_p.h DEFINES += \ diff --git a/tests/auto/gui.pro b/tests/auto/gui.pro index 186f00c..6230220 100644 --- a/tests/auto/gui.pro +++ b/tests/auto/gui.pro @@ -139,6 +139,7 @@ SUBDIRS=\ qpushbutton \ qquaternion \ qradiobutton \ + qrawfont \ qregexpvalidator \ qregion \ qscrollarea \ diff --git a/tests/auto/qglyphs/tst_qglyphs.cpp b/tests/auto/qglyphs/tst_qglyphs.cpp index 1c0aa9e..a9ae556 100644 --- a/tests/auto/qglyphs/tst_qglyphs.cpp +++ b/tests/auto/qglyphs/tst_qglyphs.cpp @@ -46,6 +46,8 @@ #include #include +#if !defined(QT_NO_RAWFONT) + // #define DEBUG_SAVE_IMAGE class tst_QGlyphs: public QObject @@ -116,7 +118,7 @@ static QGlyphs make_dummy_indexes() positions.append(QPointF(3, 4)); positions.append(QPointF(5, 6)); - glyphs.setFont(font); + glyphs.setFont(QRawFont::fromFont(font)); glyphs.setGlyphIndexes(glyphIndexes); glyphs.setPositions(positions); @@ -141,7 +143,7 @@ void tst_QGlyphs::copyConstructor() positions.append(QPointF(3, 4)); positions.append(QPointF(5, 6)); - glyphs.setFont(font); + glyphs.setFont(QRawFont::fromFont(font)); glyphs.setGlyphIndexes(glyphIndexes); glyphs.setPositions(positions); } @@ -180,14 +182,16 @@ void tst_QGlyphs::equalsOperator_data() positions[2] += QPointF(1, 1); busted.setPositions(positions); + QTest::newRow("Different positions") << one << busted << false; } { QGlyphs busted(two); - QFont font = busted.font(); - font.setPointSize(font.pointSize() * 2); - busted.setFont(font); + + QFont font; + font.setPixelSize(busted.font().pixelSize() * 2); + busted.setFont(QRawFont::fromFont(font)); QTest::newRow("Different fonts") << one << busted << false; } @@ -288,7 +292,7 @@ void tst_QGlyphs::drawNonExistentGlyphs() QGlyphs glyphs; glyphs.setGlyphIndexes(glyphIndexes); glyphs.setPositions(glyphPositions); - glyphs.setFont(m_testFont); + glyphs.setFont(QRawFont::fromFont(m_testFont)); QPixmap image(1000, 1000); image.fill(Qt::white); @@ -571,3 +575,4 @@ void tst_QGlyphs::drawRightToLeft() QTEST_MAIN(tst_QGlyphs) #include "tst_qglyphs.moc" +#endif // QT_NO_RAWFONT diff --git a/tests/auto/qrawfont/qrawfont.pro b/tests/auto/qrawfont/qrawfont.pro new file mode 100644 index 0000000..ccdccfb --- /dev/null +++ b/tests/auto/qrawfont/qrawfont.pro @@ -0,0 +1,13 @@ +load(qttest_p4) +QT = core gui + +SOURCES += \ + tst_qrawfont.cpp + +INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/harfbuzz/src + +wince*|symbian*: { + DEFINES += SRCDIR=\\\"\\\" +} else { + DEFINES += SRCDIR=\\\"$$PWD/\\\" +} diff --git a/tests/auto/qrawfont/testfont.ttf b/tests/auto/qrawfont/testfont.ttf new file mode 100644 index 0000000..d6042d2 Binary files /dev/null and b/tests/auto/qrawfont/testfont.ttf differ diff --git a/tests/auto/qrawfont/testfont_bold_italic.ttf b/tests/auto/qrawfont/testfont_bold_italic.ttf new file mode 100644 index 0000000..9f65ac8 Binary files /dev/null and b/tests/auto/qrawfont/testfont_bold_italic.ttf differ diff --git a/tests/auto/qrawfont/tst_qrawfont.cpp b/tests/auto/qrawfont/tst_qrawfont.cpp new file mode 100644 index 0000000..c20b41d --- /dev/null +++ b/tests/auto/qrawfont/tst_qrawfont.cpp @@ -0,0 +1,812 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite 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 + +#include +#include + +#if !defined(QT_NO_RAWFONT) + +class tst_QRawFont: public QObject +{ + Q_OBJECT + +private slots: + void invalidRawFont(); + + void explicitRawFontNotLoadedInDatabase_data(); + void explicitRawFontNotLoadedInDatabase(); + + void explicitRawFontNotAvailableInSystem_data(); + void explicitRawFontNotAvailableInSystem(); + + void correctFontData_data(); + void correctFontData(); + + void glyphIndices(); + + void advances_data(); + void advances(); + + void textLayout(); + + void fontTable_data(); + void fontTable(); + + void supportedWritingSystems_data(); + void supportedWritingSystems(); + + void supportsCharacter_data(); + void supportsCharacter(); + + void supportsUcs4Character_data(); + void supportsUcs4Character(); + + void fromFont_data(); + void fromFont(); + + void copyConstructor_data(); + void copyConstructor(); + + void detach_data(); + void detach(); + + void unsupportedWritingSystem_data(); + void unsupportedWritingSystem(); +}; + +Q_DECLARE_METATYPE(QFont::HintingPreference) +Q_DECLARE_METATYPE(QFont::Style) +Q_DECLARE_METATYPE(QFont::Weight) +Q_DECLARE_METATYPE(QFontDatabase::WritingSystem) + +void tst_QRawFont::invalidRawFont() +{ + QRawFont font; + QVERIFY(!font.isValid()); + QCOMPARE(font.pixelSize(), -1); + QVERIFY(font.familyName().isEmpty()); + QCOMPARE(font.style(), QFont::StyleNormal); + QCOMPARE(font.weight(), -1); + QCOMPARE(font.ascent(), 0.0); + QCOMPARE(font.descent(), 0.0); + QVERIFY(font.glyphIndexesForString(QLatin1String("Test")).isEmpty()); +} + +void tst_QRawFont::explicitRawFontNotLoadedInDatabase_data() +{ + QTest::addColumn("hintingPreference"); + + QTest::newRow("Default hinting preference") << QFont::PreferDefaultHinting; + QTest::newRow("No hinting") << QFont::PreferNoHinting; + QTest::newRow("Vertical hinting") << QFont::PreferVerticalHinting; + QTest::newRow("Full hinting") << QFont::PreferFullHinting; +} + +void tst_QRawFont::explicitRawFontNotLoadedInDatabase() +{ + QFETCH(QFont::HintingPreference, hintingPreference); + + QRawFont font(QLatin1String(SRCDIR "testfont.ttf"), 10, hintingPreference); + QVERIFY(font.isValid()); + + QVERIFY(!QFontDatabase().families().contains(font.familyName())); +} + +void tst_QRawFont::explicitRawFontNotAvailableInSystem_data() +{ + QTest::addColumn("hintingPreference"); + + QTest::newRow("Default hinting preference") << QFont::PreferDefaultHinting; + QTest::newRow("No hinting") << QFont::PreferNoHinting; + QTest::newRow("Vertical hinting") << QFont::PreferVerticalHinting; + QTest::newRow("Full hinting") << QFont::PreferFullHinting; +} + +void tst_QRawFont::explicitRawFontNotAvailableInSystem() +{ + QFETCH(QFont::HintingPreference, hintingPreference); + + QRawFont rawfont(QLatin1String(SRCDIR "testfont.ttf"), 10, hintingPreference); + + { + QFont font(rawfont.familyName(), 10); + + QVERIFY(!font.exactMatch()); + QVERIFY(font.family() != QFontInfo(font).family()); + } +} + +void tst_QRawFont::correctFontData_data() +{ + QTest::addColumn("fileName"); + QTest::addColumn("expectedFamilyName"); + QTest::addColumn("style"); + QTest::addColumn("weight"); + QTest::addColumn("hintingPreference"); + QTest::addColumn("unitsPerEm"); + QTest::addColumn("pixelSize"); + + int hintingPreferences[] = { + int(QFont::PreferDefaultHinting), + int(QFont::PreferNoHinting), + int(QFont::PreferVerticalHinting), + int(QFont::PreferFullHinting), + -1 + }; + int *hintingPreference = hintingPreferences; + + while (*hintingPreference >= 0) { + QString fileName = QLatin1String(SRCDIR "testfont.ttf"); + QString title = fileName + + QLatin1String(": hintingPreference=") + + QString::number(*hintingPreference); + + QTest::newRow(qPrintable(title)) + << fileName + << QString::fromLatin1("QtBidiTestFont") + << QFont::StyleNormal + << QFont::Normal + << QFont::HintingPreference(*hintingPreference) + << 1000.0 + << 10; + + fileName = QLatin1String(SRCDIR "testfont_bold_italic.ttf"); + title = fileName + + QLatin1String(": hintingPreference=") + + QString::number(*hintingPreference); + + QTest::newRow(qPrintable(title)) + << fileName + << QString::fromLatin1("QtBidiTestFont") + << QFont::StyleItalic + << QFont::Bold + << QFont::HintingPreference(*hintingPreference) + << 1000.0 + << 10; + + ++hintingPreference; + } +} + +void tst_QRawFont::correctFontData() +{ + QFETCH(QString, fileName); + QFETCH(QString, expectedFamilyName); + QFETCH(QFont::Style, style); + QFETCH(QFont::Weight, weight); + QFETCH(QFont::HintingPreference, hintingPreference); + QFETCH(qreal, unitsPerEm); + QFETCH(int, pixelSize); + + QRawFont font(fileName, 10, hintingPreference); + QVERIFY(font.isValid()); + + QCOMPARE(font.familyName(), expectedFamilyName); + QCOMPARE(font.style(), style); + QCOMPARE(font.weight(), int(weight)); + QCOMPARE(font.hintingPreference(), hintingPreference); + QCOMPARE(font.unitsPerEm(), unitsPerEm); + QCOMPARE(font.pixelSize(), pixelSize); +} + +void tst_QRawFont::glyphIndices() +{ + QRawFont font(QLatin1String(SRCDIR "testfont.ttf"), 10); + QVERIFY(font.isValid()); + + QVector glyphIndices = font.glyphIndexesForString(QLatin1String("Foobar")); + QVector expectedGlyphIndices; + expectedGlyphIndices << 44 << 83 << 83 << 70 << 69 << 86; + + QCOMPARE(glyphIndices, expectedGlyphIndices); +} + +void tst_QRawFont::advances_data() +{ + QTest::addColumn("hintingPreference"); + + QTest::newRow("Default hinting preference") << QFont::PreferDefaultHinting; + QTest::newRow("No hinting") << QFont::PreferNoHinting; + QTest::newRow("Vertical hinting") << QFont::PreferVerticalHinting; + QTest::newRow("Full hinting") << QFont::PreferFullHinting; +} + +void tst_QRawFont::advances() +{ + QFETCH(QFont::HintingPreference, hintingPreference); + + QRawFont font(QLatin1String(SRCDIR "testfont.ttf"), 10, hintingPreference); + QVERIFY(font.isValid()); + + QRawFontPrivate *font_d = QRawFontPrivate::get(font); + QVERIFY(font_d->fontEngine != 0); + + QVector glyphIndices; + glyphIndices << 44 << 83 << 83 << 70 << 69 << 86; // "Foobar" + + bool supportsSubPixelPositions = font_d->fontEngine->supportsSubPixelPositions(); + QVector advances = font.advancesForGlyphIndexes(glyphIndices); + for (int i=0; i 8.0); + + QVERIFY(qFuzzyIsNull(advances.at(i).y())); + } +} + +void tst_QRawFont::textLayout() +{ + QFontDatabase fontDatabase; + int id = fontDatabase.addApplicationFont(SRCDIR "testfont.ttf"); + QVERIFY(id >= 0); + + QString familyName = QString::fromLatin1("QtBidiTestFont"); + QFont font(familyName); + font.setPixelSize(18); + QCOMPARE(QFontInfo(font).family(), familyName); + + QTextLayout layout(QLatin1String("Foobar")); + layout.setFont(font); + layout.beginLayout(); + layout.createLine(); + layout.endLayout(); + + QList glyphss = layout.glyphs(); + QCOMPARE(glyphss.size(), 1); + + QGlyphs glyphs = glyphss.at(0); + + QRawFont rawFont = glyphs.font(); + QVERIFY(rawFont.isValid()); + QCOMPARE(rawFont.familyName(), familyName); + QCOMPARE(rawFont.pixelSize(), 18); + + QVector expectedGlyphIndices; + expectedGlyphIndices << 44 << 83 << 83 << 70 << 69 << 86; + + QCOMPARE(glyphs.glyphIndexes(), expectedGlyphIndices); + + QVERIFY(fontDatabase.removeApplicationFont(id)); +} + +void tst_QRawFont::fontTable_data() +{ + QTest::addColumn("tagName"); + QTest::addColumn("hintingPreference"); + QTest::addColumn("offset"); + QTest::addColumn("expectedValue"); + + QTest::newRow("Head table, magic number, default hinting") + << QByteArray("head") + << QFont::PreferDefaultHinting + << 12 + << (QSysInfo::ByteOrder == QSysInfo::BigEndian + ? 0x5F0F3CF5 + : 0xF53C0F5F); + + QTest::newRow("Head table, magic number, no hinting") + << QByteArray("head") + << QFont::PreferNoHinting + << 12 + << (QSysInfo::ByteOrder == QSysInfo::BigEndian + ? 0x5F0F3CF5 + : 0xF53C0F5F); + + QTest::newRow("Head table, magic number, vertical hinting") + << QByteArray("head") + << QFont::PreferVerticalHinting + << 12 + << (QSysInfo::ByteOrder == QSysInfo::BigEndian + ? 0x5F0F3CF5 + : 0xF53C0F5F); + + QTest::newRow("Head table, magic number, full hinting") + << QByteArray("head") + << QFont::PreferFullHinting + << 12 + << (QSysInfo::ByteOrder == QSysInfo::BigEndian + ? 0x5F0F3CF5 + : 0xF53C0F5F); +} + +void tst_QRawFont::fontTable() +{ + QFETCH(QByteArray, tagName); + QFETCH(QFont::HintingPreference, hintingPreference); + QFETCH(int, offset); + QFETCH(quint32, expectedValue); + + QRawFont font(QString::fromLatin1(SRCDIR "testfont.ttf"), 10, hintingPreference); + QVERIFY(font.isValid()); + + QByteArray table = font.fontTable(tagName); + QVERIFY(!table.isEmpty()); + + const quint32 *value = reinterpret_cast(table.constData() + offset); + QCOMPARE(*value, expectedValue); +} + +typedef QList WritingSystemList; +Q_DECLARE_METATYPE(WritingSystemList) + +void tst_QRawFont::supportedWritingSystems_data() +{ + QTest::addColumn("fileName"); + QTest::addColumn("writingSystems"); + QTest::addColumn("hintingPreference"); + + for (int hintingPreference=QFont::PreferDefaultHinting; + hintingPreference<=QFont::PreferFullHinting; + ++hintingPreference) { + + QTest::newRow(qPrintable(QString::fromLatin1("testfont.ttf, hintingPreference=%1") + .arg(hintingPreference))) + << QString::fromLatin1(SRCDIR "testfont.ttf") + << (QList() + << QFontDatabase::Latin + << QFontDatabase::Hebrew + << QFontDatabase::Vietnamese) // Vietnamese uses same unicode bits as Latin + << QFont::HintingPreference(hintingPreference); + + QTest::newRow(qPrintable(QString::fromLatin1("testfont_bold_italic.ttf, hintingPreference=%1") + .arg(hintingPreference))) + << QString::fromLatin1(SRCDIR "testfont_bold_italic.ttf") + << (QList() + << QFontDatabase::Latin + << QFontDatabase::Hebrew + << QFontDatabase::Devanagari + << QFontDatabase::Vietnamese) // Vietnamese uses same unicode bits as Latin + << QFont::HintingPreference(hintingPreference); + } +} + +void tst_QRawFont::supportedWritingSystems() +{ + QFETCH(QString, fileName); + QFETCH(WritingSystemList, writingSystems); + QFETCH(QFont::HintingPreference, hintingPreference); + + QRawFont font(fileName, 10, hintingPreference); + QVERIFY(font.isValid()); + + WritingSystemList actualWritingSystems = font.supportedWritingSystems(); + QCOMPARE(actualWritingSystems.size(), writingSystems.size()); + + foreach (QFontDatabase::WritingSystem writingSystem, writingSystems) + QVERIFY(actualWritingSystems.contains(writingSystem)); +} + +void tst_QRawFont::supportsCharacter_data() +{ + QTest::addColumn("fileName"); + QTest::addColumn("hintingPreference"); + QTest::addColumn("character"); + QTest::addColumn("shouldBeSupported"); + + const char *fileNames[2] = { + SRCDIR "testfont.ttf", + SRCDIR "testfont_bold_italic.ttf" + }; + + for (int hintingPreference=QFont::PreferDefaultHinting; + hintingPreference<=QFont::PreferFullHinting; + ++hintingPreference) { + + for (int i=0; i<2; ++i) { + QString fileName = QLatin1String(fileNames[i]); + + // Latin text + for (char ch='!'; ch<='~'; ++ch) { + QString title = QString::fromLatin1("%1, character=0x%2, hintingPreference=%3") + .arg(fileName).arg(QString::number(ch, 16)).arg(hintingPreference); + + QTest::newRow(qPrintable(title)) + << fileName + << QFont::HintingPreference(hintingPreference) + << QChar::fromLatin1(ch) + << true; + } + + // Hebrew text + for (quint16 ch=0x05D0; ch<=0x05EA; ++ch) { + QString title = QString::fromLatin1("%1, character=0x%2, hintingPreference=%3") + .arg(fileName).arg(QString::number(ch, 16)).arg(hintingPreference); + + QTest::newRow(qPrintable(title)) + << fileName + << QFont::HintingPreference(hintingPreference) + << QChar(ch) + << true; + } + + QTest::newRow(qPrintable(QString::fromLatin1("Missing character, %1, hintingPreference=%2") + .arg(fileName).arg(hintingPreference))) + << fileName + << QFont::HintingPreference(hintingPreference) + << QChar(0xD8) + << false; + } + } +} + +void tst_QRawFont::supportsCharacter() +{ + QFETCH(QString, fileName); + QFETCH(QFont::HintingPreference, hintingPreference); + QFETCH(QChar, character); + QFETCH(bool, shouldBeSupported); + + QRawFont font(fileName, 10, hintingPreference); + QVERIFY(font.isValid()); + + QCOMPARE(font.supportsCharacter(character), shouldBeSupported); +} + +void tst_QRawFont::supportsUcs4Character_data() +{ + QTest::addColumn("fileName"); + QTest::addColumn("hintingPreference"); + QTest::addColumn("ucs4"); + QTest::addColumn("shouldBeSupported"); + + // Gothic text + for (int hintingPreference=QFont::PreferDefaultHinting; + hintingPreference<=QFont::PreferFullHinting; + ++hintingPreference) { + for (quint32 ch=0x10330; ch<=0x1034A; ++ch) { + { + QString fileName = QString::fromLatin1(SRCDIR "testfont.ttf"); + QString title = QString::fromLatin1("%1, character=0x%2, hintingPreference=%3") + .arg(fileName).arg(QString::number(ch, 16)).arg(hintingPreference); + + QTest::newRow(qPrintable(title)) + << fileName + << QFont::HintingPreference(hintingPreference) + << ch + << true; + } + + { + QString fileName = QString::fromLatin1(SRCDIR "testfont_bold_italic.ttf"); + QString title = QString::fromLatin1("%1, character=0x%2, hintingPreference=%3") + .arg(fileName).arg(QString::number(ch, 16)).arg(hintingPreference); + + QTest::newRow(qPrintable(title)) + << fileName + << QFont::HintingPreference(hintingPreference) + << ch + << false; + } + } + } +} + +void tst_QRawFont::supportsUcs4Character() +{ + QFETCH(QString, fileName); + QFETCH(QFont::HintingPreference, hintingPreference); + QFETCH(quint32, ucs4); + QFETCH(bool, shouldBeSupported); + + QRawFont font(fileName, 10, hintingPreference); + QVERIFY(font.isValid()); + + QCOMPARE(font.supportsCharacter(ucs4), shouldBeSupported); +} + +void tst_QRawFont::fromFont_data() +{ + QTest::addColumn("fileName"); + QTest::addColumn("hintingPreference"); + QTest::addColumn("familyName"); + QTest::addColumn("writingSystem"); + + for (int i=QFont::PreferDefaultHinting; i<=QFont::PreferFullHinting; ++i) { + QString titleBase = QString::fromLatin1("%2, hintingPreference=%1, writingSystem=%3") + .arg(i); + { + QString fileName = QString::fromLatin1(SRCDIR "testfont.ttf"); + QFontDatabase::WritingSystem writingSystem = QFontDatabase::Any; + + QString title = titleBase.arg(fileName).arg(writingSystem); + QTest::newRow(qPrintable(title)) + << fileName + << QFont::HintingPreference(i) + << "QtBidiTestFont" + << writingSystem; + } + + { + QString fileName = QString::fromLatin1(SRCDIR "testfont.ttf"); + QFontDatabase::WritingSystem writingSystem = QFontDatabase::Hebrew; + + QString title = titleBase.arg(fileName).arg(writingSystem); + QTest::newRow(qPrintable(title)) + << fileName + << QFont::HintingPreference(i) + << "QtBidiTestFont" + << writingSystem; + } + + { + QString fileName = QString::fromLatin1(SRCDIR "testfont.ttf"); + QFontDatabase::WritingSystem writingSystem = QFontDatabase::Latin; + + QString title = titleBase.arg(fileName).arg(writingSystem); + QTest::newRow(qPrintable(title)) + << fileName + << QFont::HintingPreference(i) + << "QtBidiTestFont" + << writingSystem; + } + } +} + +void tst_QRawFont::fromFont() +{ + QFETCH(QString, fileName); + QFETCH(QFont::HintingPreference, hintingPreference); + QFETCH(QString, familyName); + QFETCH(QFontDatabase::WritingSystem, writingSystem); + + QFontDatabase fontDatabase; + int id = fontDatabase.addApplicationFont(fileName); + QVERIFY(id >= 0); + + QFont font(familyName); + font.setHintingPreference(hintingPreference); + font.setPixelSize(26); + + QRawFont rawFont = QRawFont::fromFont(font, writingSystem); + QVERIFY(rawFont.isValid()); + QCOMPARE(rawFont.familyName(), familyName); + QCOMPARE(rawFont.pixelSize(), 26); + + QVERIFY(fontDatabase.removeApplicationFont(id)); +} + +void tst_QRawFont::copyConstructor_data() +{ + QTest::addColumn("hintingPreference"); + + QTest::newRow("Default hinting preference") << QFont::PreferDefaultHinting; + QTest::newRow("No hinting preference") << QFont::PreferNoHinting; + QTest::newRow("Vertical hinting preference") << QFont::PreferVerticalHinting; + QTest::newRow("Full hinting preference") << QFont::PreferFullHinting; +} + +void tst_QRawFont::copyConstructor() +{ + QFETCH(QFont::HintingPreference, hintingPreference); + + { + QString rawFontFamilyName; + int rawFontPixelSize; + qreal rawFontAscent; + qreal rawFontDescent; + int rawFontTableSize; + + QRawFont outerRawFont; + { + QRawFont rawFont(QString::fromLatin1(SRCDIR "testfont.ttf"), 11, hintingPreference); + QVERIFY(rawFont.isValid()); + + rawFontFamilyName = rawFont.familyName(); + rawFontPixelSize = rawFont.pixelSize(); + rawFontAscent = rawFont.ascent(); + rawFontDescent = rawFont.descent(); + rawFontTableSize = rawFont.fontTable("glyf").size(); + QVERIFY(rawFontTableSize > 0); + + { + QRawFont otherRawFont(rawFont); + QVERIFY(otherRawFont.isValid()); + QCOMPARE(otherRawFont.pixelSize(), rawFontPixelSize); + QCOMPARE(otherRawFont.familyName(), rawFontFamilyName); + QCOMPARE(otherRawFont.hintingPreference(), hintingPreference); + QCOMPARE(otherRawFont.ascent(), rawFontAscent); + QCOMPARE(otherRawFont.descent(), rawFontDescent); + QCOMPARE(otherRawFont.fontTable("glyf").size(), rawFontTableSize); + } + + { + QRawFont otherRawFont = rawFont; + QVERIFY(otherRawFont.isValid()); + QCOMPARE(otherRawFont.pixelSize(), rawFontPixelSize); + QCOMPARE(otherRawFont.familyName(), rawFontFamilyName); + QCOMPARE(otherRawFont.hintingPreference(), hintingPreference); + QCOMPARE(otherRawFont.ascent(), rawFontAscent); + QCOMPARE(otherRawFont.descent(), rawFontDescent); + QCOMPARE(otherRawFont.fontTable("glyf").size(), rawFontTableSize); + } + + outerRawFont = rawFont; + } + + QVERIFY(outerRawFont.isValid()); + QCOMPARE(outerRawFont.pixelSize(), rawFontPixelSize); + QCOMPARE(outerRawFont.familyName(), rawFontFamilyName); + QCOMPARE(outerRawFont.hintingPreference(), hintingPreference); + QCOMPARE(outerRawFont.ascent(), rawFontAscent); + QCOMPARE(outerRawFont.descent(), rawFontDescent); + QCOMPARE(outerRawFont.fontTable("glyf").size(), rawFontTableSize); + } +} + +void tst_QRawFont::detach_data() +{ + QTest::addColumn("hintingPreference"); + + QTest::newRow("Default hinting preference") << QFont::PreferDefaultHinting; + QTest::newRow("No hinting preference") << QFont::PreferNoHinting; + QTest::newRow("Vertical hinting preference") << QFont::PreferVerticalHinting; + QTest::newRow("Full hinting preference") << QFont::PreferFullHinting; +} + +void tst_QRawFont::detach() +{ + QFETCH(QFont::HintingPreference, hintingPreference); + + { + QString rawFontFamilyName; + int rawFontPixelSize; + qreal rawFontAscent; + qreal rawFontDescent; + int rawFontTableSize; + + QRawFont outerRawFont; + { + QRawFont rawFont(QString::fromLatin1(SRCDIR "testfont.ttf"), 11, hintingPreference); + QVERIFY(rawFont.isValid()); + + rawFontFamilyName = rawFont.familyName(); + rawFontPixelSize = rawFont.pixelSize(); + rawFontAscent = rawFont.ascent(); + rawFontDescent = rawFont.descent(); + rawFontTableSize = rawFont.fontTable("glyf").size(); + QVERIFY(rawFontTableSize > 0); + + { + QRawFont otherRawFont(rawFont); + + otherRawFont.loadFromFile(QLatin1String(SRCDIR "testfont.ttf"), + rawFontPixelSize, hintingPreference); + + QVERIFY(otherRawFont.isValid()); + QCOMPARE(otherRawFont.pixelSize(), rawFontPixelSize); + QCOMPARE(otherRawFont.familyName(), rawFontFamilyName); + QCOMPARE(otherRawFont.hintingPreference(), hintingPreference); + QCOMPARE(otherRawFont.ascent(), rawFontAscent); + QCOMPARE(otherRawFont.descent(), rawFontDescent); + QCOMPARE(otherRawFont.fontTable("glyf").size(), rawFontTableSize); + } + + { + QRawFont otherRawFont = rawFont; + + otherRawFont.loadFromFile(QLatin1String(SRCDIR "testfont.ttf"), + rawFontPixelSize, hintingPreference); + + QVERIFY(otherRawFont.isValid()); + QCOMPARE(otherRawFont.pixelSize(), rawFontPixelSize); + QCOMPARE(otherRawFont.familyName(), rawFontFamilyName); + QCOMPARE(otherRawFont.hintingPreference(), hintingPreference); + QCOMPARE(otherRawFont.ascent(), rawFontAscent); + QCOMPARE(otherRawFont.descent(), rawFontDescent); + QCOMPARE(otherRawFont.fontTable("glyf").size(), rawFontTableSize); + } + + outerRawFont = rawFont; + + rawFont.loadFromFile(QLatin1String(SRCDIR "testfont.ttf"), rawFontPixelSize, + hintingPreference); + } + + QVERIFY(outerRawFont.isValid()); + QCOMPARE(outerRawFont.pixelSize(), rawFontPixelSize); + QCOMPARE(outerRawFont.familyName(), rawFontFamilyName); + QCOMPARE(outerRawFont.hintingPreference(), hintingPreference); + QCOMPARE(outerRawFont.ascent(), rawFontAscent); + QCOMPARE(outerRawFont.descent(), rawFontDescent); + QCOMPARE(outerRawFont.fontTable("glyf").size(), rawFontTableSize); + } +} + +void tst_QRawFont::unsupportedWritingSystem_data() +{ + QTest::addColumn("hintingPreference"); + + QTest::newRow("Default hinting preference") << QFont::PreferDefaultHinting; + QTest::newRow("No hinting preference") << QFont::PreferNoHinting; + QTest::newRow("Vertical hinting preference") << QFont::PreferVerticalHinting; + QTest::newRow("Full hinting preference") << QFont::PreferFullHinting; +} + +void tst_QRawFont::unsupportedWritingSystem() +{ + QFETCH(QFont::HintingPreference, hintingPreference); + + QFontDatabase fontDatabase; + int id = fontDatabase.addApplicationFont(QLatin1String(SRCDIR "testfont.ttf")); + + QFont font("QtBidiTestFont"); + font.setHintingPreference(hintingPreference); + font.setPixelSize(12); + + QRawFont rawFont = QRawFont::fromFont(font, QFontDatabase::Any); + QCOMPARE(rawFont.familyName(), QString::fromLatin1("QtBidiTestFont")); + QCOMPARE(rawFont.pixelSize(), 12); + + rawFont = QRawFont::fromFont(font, QFontDatabase::Hebrew); + QCOMPARE(rawFont.familyName(), QString::fromLatin1("QtBidiTestFont")); + QCOMPARE(rawFont.pixelSize(), 12); + + QString arabicText = QFontDatabase::writingSystemSample(QFontDatabase::Arabic); + + QTextLayout layout; + layout.setFont(font); + layout.setText(arabicText); + layout.beginLayout(); + layout.createLine(); + layout.endLayout(); + + QList glyphss = layout.glyphs(); + QCOMPARE(glyphss.size(), 1); + + QGlyphs glyphs = glyphss.at(0); + QRawFont layoutFont = glyphs.font(); + QVERIFY(layoutFont.familyName() != QString::fromLatin1("QtBidiTestFont")); + QCOMPARE(layoutFont.pixelSize(), 12); + + rawFont = QRawFont::fromFont(font, QFontDatabase::Arabic); + QCOMPARE(rawFont.familyName(), layoutFont.familyName()); + QCOMPARE(rawFont.pixelSize(), 12); + + fontDatabase.removeApplicationFont(id); +} + +QTEST_MAIN(tst_QRawFont) +#include "tst_qrawfont.moc" + +#endif // QT_NO_RAWFONT -- cgit v0.12 From 6c121991f85164d257208b14845c7ff913a687f4 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 18 Apr 2011 09:51:13 +0200 Subject: Make sure #ifdef'd tests still have main() function Otherwise it won't link on QWS Reviewed-by: TrustMe --- tests/auto/qglyphs/tst_qglyphs.cpp | 10 +++++++--- tests/auto/qrawfont/tst_qrawfont.cpp | 8 +++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/tests/auto/qglyphs/tst_qglyphs.cpp b/tests/auto/qglyphs/tst_qglyphs.cpp index a9ae556..ffa0d00 100644 --- a/tests/auto/qglyphs/tst_qglyphs.cpp +++ b/tests/auto/qglyphs/tst_qglyphs.cpp @@ -46,14 +46,13 @@ #include #include -#if !defined(QT_NO_RAWFONT) - // #define DEBUG_SAVE_IMAGE class tst_QGlyphs: public QObject { Q_OBJECT +#if !defined(QT_NO_RAWFONT) private slots: void initTestCase(); void cleanupTestCase(); @@ -77,8 +76,12 @@ private slots: private: int m_testFontId; QFont m_testFont; +#endif // QT_NO_RAWFONT + }; +#if !defined(QT_NO_RAWFONT) + Q_DECLARE_METATYPE(QGlyphs); void tst_QGlyphs::initTestCase() @@ -572,7 +575,8 @@ void tst_QGlyphs::drawRightToLeft() } +#endif // QT_NO_RAWFONT + QTEST_MAIN(tst_QGlyphs) #include "tst_qglyphs.moc" -#endif // QT_NO_RAWFONT diff --git a/tests/auto/qrawfont/tst_qrawfont.cpp b/tests/auto/qrawfont/tst_qrawfont.cpp index c20b41d..3aa4006 100644 --- a/tests/auto/qrawfont/tst_qrawfont.cpp +++ b/tests/auto/qrawfont/tst_qrawfont.cpp @@ -44,12 +44,11 @@ #include #include -#if !defined(QT_NO_RAWFONT) - class tst_QRawFont: public QObject { Q_OBJECT +#if !defined(QT_NO_RAWFONT) private slots: void invalidRawFont(); @@ -92,8 +91,10 @@ private slots: void unsupportedWritingSystem_data(); void unsupportedWritingSystem(); +#endif // QT_NO_RAWFONT }; +#if !defined(QT_NO_RAWFONT) Q_DECLARE_METATYPE(QFont::HintingPreference) Q_DECLARE_METATYPE(QFont::Style) Q_DECLARE_METATYPE(QFont::Weight) @@ -806,7 +807,8 @@ void tst_QRawFont::unsupportedWritingSystem() fontDatabase.removeApplicationFont(id); } +#endif // QT_NO_RAWFONT + QTEST_MAIN(tst_QRawFont) #include "tst_qrawfont.moc" -#endif // QT_NO_RAWFONT -- cgit v0.12 From 63bf7cd581d9f69fecae82921d5c2c5b5eddc04a Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 19 Apr 2011 12:05:48 +0200 Subject: Fix wrong merge of 3aa39b0164ce4bb9e --- qmake/generators/makefile.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qmake/generators/makefile.cpp b/qmake/generators/makefile.cpp index 83d3adf..4f3b113 100644 --- a/qmake/generators/makefile.cpp +++ b/qmake/generators/makefile.cpp @@ -2901,7 +2901,7 @@ MakefileGenerator::fileFixify(const QString& file, const QString &out_d, const Q ret = "."; debug_msg(3, "Fixed[%d,%d] %s :: to :: %s [%s::%s] [%s::%s]", fix, canon, orig_file.toLatin1().constData(), ret.toLatin1().constData(), in_d.toLatin1().constData(), out_d.toLatin1().constData(), - pwd.toLatin1().constData(), Option::output_dir.toLatin1().constData()); + qmake_getpwd().toLatin1().constData(), Option::output_dir.toLatin1().constData()); return ret; } -- cgit v0.12 From cd1a52099e4154ecaf4862d2248ddb1565b3c3ab Mon Sep 17 00:00:00 2001 From: Victor Ostashevsky Date: Tue, 19 Apr 2011 13:43:39 +0200 Subject: Ukrainian translation updated Merge-request: 1189 Reviewed-by: Oswald Buddenhagen --- translations/linguist_uk.ts | 4 +++ translations/qt_uk.ts | 69 ++++++++++++++++++++++++++++++++++++++++++++- translations/qtconfig_uk.ts | 20 +++++++++++++ 3 files changed, 92 insertions(+), 1 deletion(-) diff --git a/translations/linguist_uk.ts b/translations/linguist_uk.ts index 56db6ba..a503475 100644 --- a/translations/linguist_uk.ts +++ b/translations/linguist_uk.ts @@ -86,6 +86,10 @@ DataModel + The translation file '%1' will not be loaded because it is empty. + Файл перекладу '%1' не буде завантажено, бо він порожній. + + <qt>Duplicate messages found in '%1': <qt>Повідомлення-дублікати знайдено в '%1': diff --git a/translations/qt_uk.ts b/translations/qt_uk.ts index 7f396ad..52e70a2 100644 --- a/translations/qt_uk.ts +++ b/translations/qt_uk.ts @@ -321,6 +321,10 @@ have libgstreamer-plugins-base installed. Playback complete Відтворення завершене + + Download error + Помилка звантаження + Phonon::MMF::AbstractVideoPlayer @@ -440,6 +444,10 @@ have libgstreamer-plugins-base installed. Error opening source: media type could not be determined Помилка відкриття джерела: не вдалося визначити тип медіа-даних + + Failed to set requested IAP + Збій встановлення точки доступу до Інтернет + Phonon::MMF::StereoWidening @@ -1200,6 +1208,11 @@ to %1: недостатньо ресурсів + %1: permission denied + QSystemSemaphore + %1: доступ заборонено + + %1: unknown error %2 QSystemSemaphore %1: невідома помилка %2 @@ -1366,6 +1379,13 @@ to + QDeclarativeApplication + + Application is an abstract class + Application - це абстрактний клас + + + QDeclarativeBehavior Cannot change the animation assigned to a Behavior. @@ -1493,6 +1513,14 @@ to Неможливо створити порожню специфікацію компоненти + "%1.%2" is not available in %3 %4.%5. + "%1.%2" не доступно в %3 %4.%5. + + + "%1.%2" is not available due to component versioning. + "%1.%2" не доступно через версіювання компонента. + + Incorrectly specified signal assignment Неправильно вказане призначення сигналу @@ -1589,6 +1617,10 @@ to Неправильне присвоєння властивості: очікувався скрипт + Cannot assign multiple values to a singular property + Неможливо присвоїти декілька значенть до одиничної властивості + + Cannot assign object to property Неможливо призначити об'єкт властивості @@ -1681,8 +1713,16 @@ to Непраильна позиція псевдоніму + Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property> + Неправильне посилання на псевдонім. Посилання на псевдонім повинно бути вказане як <id>, <id>.<властивість> або <id>.<властивість-значення>.<властивість> + + + Alias property exceeds alias bounds + Властивість-псевдонім виходить за межі псевдоніму + + Invalid alias reference. An alias reference must be specified as <id> or <id>.<property> - Неправильне посилання на псевдонім. Посилання на псевдонім має бути вказане, як <id> або <id>.<property> + Неправильне посилання на псевдонім. Посилання на псевдонім має бути вказане, як <id> або <id>.<property> Invalid alias reference. Unable to find id "%1" @@ -1695,6 +1735,10 @@ to Invalid empty URL Неправильний порожній URL + + createObject: value is not an object + createObject: значення не є об’єктом + QDeclarativeConnections @@ -1756,6 +1800,10 @@ to QDeclarativeImportDatabase + cannot load module "%1": File name case mismatch for "%2" + неможливо завантажити модуль "%1": Регістр імені файлу не збігається для "%2" + + module "%1" definition "%2" not readable неможливо прочитати визначення "%2" модуля "%1" @@ -1811,6 +1859,10 @@ to is not a type не є типом + + File name case mismatch for "%2" + Регістр імені файлу не збігається для "%2" + QDeclarativeKeyNavigationAttached @@ -1827,6 +1879,17 @@ to + QDeclarativeLayoutMirroringAttached + + LayoutDirection attached property only works with Items + Прикріплена властивість LayoutDirection працює лише з Item + + + LayoutMirroring is only available via attached properties + LayoutMirroring доступна лише через прикріплені властивості + + + QDeclarativeListModel remove: index %1 out of range @@ -6591,6 +6654,10 @@ Do you want to overwrite it? Error during SSL handshake: %1 Помилка рукостискання SSL: %1 + + The peer certificate is blacklisted + Сертифікат іншої сторони в чорному списку + QStateMachine diff --git a/translations/qtconfig_uk.ts b/translations/qtconfig_uk.ts index 3b1e2e5..24a9b7d 100644 --- a/translations/qtconfig_uk.ts +++ b/translations/qtconfig_uk.ts @@ -4,6 +4,26 @@ MainWindow + <p><b><font size+=2>Appearance</font></b></p><hr><p>Use this tab to customize the appearance of your Qt applications.</p><p>You can select the default GUI Style from the drop down list and customize the colors.</p><p>Any GUI Style plugins in your plugin path will automatically be added to the list of built-in Qt styles. (See the Library Paths tab for information on adding new plugin paths.)</p><p>When you choose 3-D Effects and Window Background colors, the Qt Configuration program will automatically generate a palette for you. To customize colors further, press the Tune Palette button to open the advanced palette editor.<p>The Preview Window shows what the selected Style and colors look like. + + + + <p><b><font size+=2>Fonts</font></b></p><hr><p>Use this tab to select the default font for your Qt applications. The selected font is shown (initially as 'Sample Text') in the line edit below the Family, Style and Point Size drop down lists.</p><p>Qt has a powerful font substitution feature that allows you to specify a list of substitute fonts. Substitute fonts are used when a font cannot be loaded, or if the specified font doesn't have a particular character.<p>For example, if you select the font Lucida, which doesn't have Korean characters, but need to show some Korean text using the Mincho font family you can do so by adding Mincho to the list. Once Mincho is added, any Korean characters that are not found in the Lucida font will be taken from the Mincho font. Because the font substitutions are lists, you can also select multiple families, such as Song Ti (for use with Chinese text). + + + + <p><b><font size+=2>Interface</font></b></p><hr><p>Use this tab to customize the feel of your Qt applications.</p><p>If the Resolve Symlinks checkbox is checked Qt will follow symlinks when handling URLs. For example, in the file dialog, if this setting is turned on and /usr/tmp is a symlink to /var/tmp, entering the /usr/tmp directory will cause the file dialog to change to /var/tmp. With this setting turned off, symlinks are not resolved or followed.</p><p>The Global Strut setting is useful for people who require a minimum size for all widgets (e.g. when using a touch panel or for users who are visually impaired). Leaving the Global Strut width and height at 0 will disable the Global Strut feature</p><p>XIM (Extended Input Methods) are used for entering characters in languages that have large character sets, for example, Chinese and Japanese. + + + + <p><b><font size+=2>Printer</font></b></p><hr><p>Use this tab to configure the way Qt generates output for the printer.You can specify if Qt should try to embed fonts into its generated output.If you enable font embedding, the resulting postscript will be more portable and will more accurately reflect the visual output on the screen; however the resulting postscript file size will be bigger.<p>When using font embedding you can select additional directories where Qt should search for embeddable font files. By default, the X server font path is used. + + + + <p><b><font size+=2>Phonon</font></b></p><hr><p>Use this tab to configure the Phonon GStreamer multimedia backend. <p>It is reccommended to leave all settings on "Auto" to let Phonon determine your settings automatically. + + + Desktop Settings (Default) Налаштування стільниці (Типово) -- cgit v0.12 From 8bc3b7cc5d7ee52962e06a1d4fdbbfb439cfa416 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 19 Apr 2011 12:15:21 +0100 Subject: Fix qfile autotest hanging in CI system The test machine is configured to pop up dialogs in case of CRT assertion failures. The CRT has a debug assert whenever an invalid file handle is used, while the test is expecting to get the EBADF return code. Due to some behaviour change in windows 7 (maybe SP1), we need to call _CrtSetReportMode in addition to setting an error handler. Reviewed-By: mread --- tests/auto/qfile/tst_qfile.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tests/auto/qfile/tst_qfile.cpp b/tests/auto/qfile/tst_qfile.cpp index 79539c9..688a92d 100644 --- a/tests/auto/qfile/tst_qfile.cpp +++ b/tests/auto/qfile/tst_qfile.cpp @@ -3294,13 +3294,18 @@ public: static void ignore_invalid_parameter(const wchar_t*, const wchar_t*, const wchar_t*, unsigned int, uintptr_t) {} AutoIgnoreInvalidParameter() { - old = _set_invalid_parameter_handler(ignore_invalid_parameter); + oldHandler = _set_invalid_parameter_handler(ignore_invalid_parameter); + //also disable the abort/retry/ignore popup + oldReportMode = _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG); } ~AutoIgnoreInvalidParameter() { - _set_invalid_parameter_handler(old); + //restore previous settings + _set_invalid_parameter_handler(oldHandler); + _CrtSetReportMode(_CRT_ASSERT, oldReportMode); } - _invalid_parameter_handler old; + _invalid_parameter_handler oldHandler; + int oldReportMode; #endif }; -- cgit v0.12 From 5888b7d01c05c03bc06a6672a4a8be30bc4192f5 Mon Sep 17 00:00:00 2001 From: Shane Kearns Date: Tue, 19 Apr 2011 14:37:05 +0100 Subject: Fix compile error with QT_NO_OPENSSL --- tests/auto/qnetworkreply/tst_qnetworkreply.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp index 146d2f3..f509cea 100644 --- a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp @@ -93,7 +93,9 @@ Q_DECLARE_METATYPE(QNetworkReply::NetworkError) Q_DECLARE_METATYPE(QBuffer*) Q_DECLARE_METATYPE(QHttpMultiPart *) Q_DECLARE_METATYPE(QList) // for multiparts +#ifndef QT_NO_OPENSSL Q_DECLARE_METATYPE(QSslConfiguration) +#endif class QNetworkReplyPtr: public QSharedPointer { -- cgit v0.12 From e93ef151eb7bc42e8139e2dc2d4ae3b7853b1c2d Mon Sep 17 00:00:00 2001 From: Sergey Belyashov Date: Tue, 19 Apr 2011 16:12:18 +0200 Subject: Updated Russian translation Merge-request: 2596 Reviewed-by: Oswald Buddenhagen --- translations/assistant_ru.ts | 12 +- translations/designer_ru.ts | 6 +- translations/linguist_ru.ts | 12 +- translations/qt_ru.ts | 655 +++++++++++++++++++++++-------------------- 4 files changed, 366 insertions(+), 319 deletions(-) diff --git a/translations/assistant_ru.ts b/translations/assistant_ru.ts index 6743986..b16f940 100644 --- a/translations/assistant_ru.ts +++ b/translations/assistant_ru.ts @@ -372,14 +372,14 @@ Reason: вместо стандартного -showUrl ссылка Отобразить документ по ссылке. -enableRemoteControl Включение удалённого управления Assistant. --show виджет Отображение указанного прикрепляемого виджета, - который может быть "contents", "index", +-show панель Отображение указанной панели, + которая может быть "contents", "index", "bookmarks" или "search". --activate виджет Включение указанного прикрепляемого виджета, - который может быть "contents", "index", +-activate панель Включение указанной панели, + которая может быть "contents", "index", "bookmarks" или "search". --hide виджет Скрытие указанного прикрепляемого виджета, - который может быть "contents", "index", +-hide панель Скрытие указанной панели, + которая может быть "contents", "index", "bookmarks" или "search". -register файлСправки Регистрация указанного файла справки (.qch) в данном файле коллекции. diff --git a/translations/designer_ru.ts b/translations/designer_ru.ts index 1b0b939..fec098c 100644 --- a/translations/designer_ru.ts +++ b/translations/designer_ru.ts @@ -439,7 +439,7 @@ Add Dock Window - Добавить прикрепляемое окно + Добавить панель Adjust Size of '%1' @@ -2699,7 +2699,7 @@ Do you want to replace it? newPrefix - + <p><b>Warning:</b> The file</p><p>%1</p><p>is outside of the current resource file's parent directory.</p> @@ -3222,7 +3222,7 @@ Do you want overwrite the template? Dock views - Прикрепляемые панели + Панели File diff --git a/translations/linguist_ru.ts b/translations/linguist_ru.ts index dfda98e..e5f57de 100644 --- a/translations/linguist_ru.ts +++ b/translations/linguist_ru.ts @@ -86,6 +86,10 @@ DataModel + The translation file '%1' will not be loaded because it is empty. + Невозможно загрузить файл перевода "%1", так как он пуст. + + <qt>Duplicate messages found in '%1': <qt>В '%1' обнаружены повторяющиеся сообщения: @@ -1268,7 +1272,7 @@ lupdate - это один из инструментов Qt Linguist. Он изв Phrases and guesses - Фразы и похожие переводы + Похожие переводы Sources and Forms @@ -1633,7 +1637,7 @@ All files (*) &Phrases - Фра&зы + &Глоссарии &Close Phrase Book @@ -1657,7 +1661,7 @@ All files (*) Vie&ws - Вид&ы + &Панели &Toolbars @@ -1977,7 +1981,7 @@ All files (*) &Display guesses - &Предлагать похожие + П&охожие переводы Set whether or not to display translation guesses. diff --git a/translations/qt_ru.ts b/translations/qt_ru.ts index e20fc0c..d399b6d 100644 --- a/translations/qt_ru.ts +++ b/translations/qt_ru.ts @@ -89,7 +89,7 @@ Revert back to device '%1' - Возвращение к устройству "%1" + Возвращение к устройству «%1» <html>Switching to the audio playback device <b>%1</b><br/>which has higher preference or is specifically configured for this stream.</html> @@ -188,7 +188,7 @@ have libgstreamer-plugins-base installed. Underflow - Переполнение + Ниже границы Already exists @@ -240,7 +240,7 @@ have libgstreamer-plugins-base installed. Server alert - Сигнал сервера + Сигнал сервера Invalid protocol @@ -444,6 +444,10 @@ have libgstreamer-plugins-base installed. Error opening source: media type could not be determined Ошибка открытия источника: не удалось определить тип медиа-данных + + Failed to set requested IAP + Не удалось задать указанную точку доступа + Phonon::MMF::StereoWidening @@ -482,7 +486,7 @@ have libgstreamer-plugins-base installed. Ambiguous %1 not handled - + Неоднозначная комбинация %1 не обработана @@ -704,7 +708,7 @@ have libgstreamer-plugins-base installed. <qt>Are you sure you wish to delete %1 "%2"?</qt> - <qt>Вы действительно хотите удалить %1 "%2"?</qt> + <qt>Вы действительно хотите удалить %1 «%2»?</qt> &Yes @@ -951,35 +955,35 @@ to Q3UrlOperator The protocol `%1' is not supported - Протокол "%1" не поддерживается + Протокол «%1» не поддерживается The protocol `%1' does not support listing directories - Протокол "%1" не поддерживает просмотр каталогов + Протокол «%1» не поддерживает просмотр каталогов The protocol `%1' does not support creating new directories - Протокол "%1" не поддерживает создание каталогов + Протокол «%1» не поддерживает создание каталогов The protocol `%1' does not support removing files or directories - Протокол "%1" не поддерживает удаление файлов или каталогов + Протокол «%1» не поддерживает удаление файлов или каталогов The protocol `%1' does not support renaming files or directories - Протокол "%1" не поддерживает переименование файлов или каталогов + Протокол «%1» не поддерживает переименование файлов или каталогов The protocol `%1' does not support getting files - Протокол "%1" не поддерживает доставку файлов + Протокол «%1» не поддерживает передачу файлов The protocol `%1' does not support putting files - Протокол "%1" не поддерживает отправку файлов + Протокол «%1» не поддерживает отправку файлов The protocol `%1' does not support copying or moving files or directories - Протокол "%1" не поддерживает копирование или перемещение файлов или каталогов + Протокол «%1» не поддерживает копирование или перемещение файлов или каталогов (unknown) @@ -1066,7 +1070,7 @@ to QApplication Executable '%1' requires Qt %2, found Qt %3. - Программный модуль "%1" требует Qt %2, найдена версия %3. + Программный модуль «%1» требует Qt %2, найдена версия %3. Incompatible Qt Library Error @@ -1219,6 +1223,11 @@ to %1: недостаточно ресурсов + %1: permission denied + QSystemSemaphore + %1: доступ запрещён + + %1: unknown error %2 QSystemSemaphore %1: неизвестная ошибка %2 @@ -1293,11 +1302,11 @@ to QDeclarativeAbstractAnimation Cannot animate non-existent property "%1" - Невозможно анимировать несуществуещее свойство "%1" + Невозможно анимировать несуществуещее свойство «%1» Cannot animate read-only property "%1" - Невозможно анимировать свойство только для чтения "%1" + Невозможно анимировать свойство только для чтения «%1» Animation is an abstract class @@ -1315,51 +1324,51 @@ to QDeclarativeAnchors Possible anchor loop detected on fill. - Обнаружена возможная цикличная привязка на fill. + Обнаружена возможная цикличная привязка на fill. Possible anchor loop detected on centerIn. - Обнаружена возможная цикличная привязка на centerIn. + Обнаружена возможная цикличная привязка на centerIn. Cannot anchor to an item that isn't a parent or sibling. - Невозможно установить привязку к элементу, не являющемуся родителем или соседом. + Невозможно установить привязку к элементу, не являющемуся родителем или соседом. Possible anchor loop detected on vertical anchor. - Обнаружена возможная цикличная привязка к вертикальной привязке. + Обнаружена возможная цикличная привязка к вертикальной привязке. Possible anchor loop detected on horizontal anchor. - Обнаружена возможная цикличная привязка к горизонтальной привязке. + Обнаружена возможная цикличная привязка к горизонтальной привязке. Cannot specify left, right, and hcenter anchors. - Невозможно задать левую, правую и среднюю привязки. + Невозможно задать левую, правую и среднюю привязки. Cannot anchor to a null item. - Невозможно привязаться к нулевому элементу. + Невозможно привязаться к нулевому элементу. Cannot anchor a horizontal edge to a vertical edge. - Невозможно привязать горизонтальный край к вертикальному. + Невозможно привязать горизонтальный край к вертикальному. Cannot anchor item to self. - Невозможно привязать элемент к самому себе. + Невозможно привязать элемент к самому себе. Cannot specify top, bottom, and vcenter anchors. - Невозможно задать верхнюю, нижнюю и среднюю привязки. + Невозможно задать верхнюю, нижнюю и среднюю привязки. Baseline anchor cannot be used in conjunction with top, bottom, or vcenter anchors. - Невозможно использовать базовую привязку вместе с верхней, нижней и центральной по вертикали. + Невозможно использовать базовую привязку вместе с верхней, нижней и центральной по вертикали. Cannot anchor a vertical edge to a horizontal edge. - Невозможно привязать вертикальный край к горизонтальному. + Невозможно привязать вертикальный край к горизонтальному. @@ -1370,31 +1379,38 @@ to + QDeclarativeApplication + + Application is an abstract class + Класс Application - абстрактный + + + QDeclarativeBehavior Cannot change the animation assigned to a Behavior. - Невозможно изменить анимацию, назначенную поведению. + Невозможно изменить анимацию, назначенную поведению. QDeclarativeBinding Binding loop detected for property "%1" - Обнаружено зацикливание привязки для свойства "%1" + Обнаружено зацикливание привязки для свойства «%1» QDeclarativeCompiledBindings Binding loop detected for property "%1" - Обнаружена цикличная привязка для свойства "%1" + Обнаружена цикличная привязка для свойства «%1» QDeclarativeCompiler Invalid property assignment: "%1" is a read-only property - Некорректное присваивание свойства: "%1" свойство только для чтения + Некорректное присваивание свойства: «%1» свойство только для чтения Invalid property assignment: unknown enumeration @@ -1402,19 +1418,19 @@ to Invalid property assignment: string expected - Некорректное присваивание свойства: ожидается значение типа "string" + Некорректное присваивание свойства: ожидается значение типа «string» Invalid property assignment: url expected - Некорректное присваивание свойства: ожидается значение типа "url" + Некорректное присваивание свойства: ожидается значение типа «url» Invalid property assignment: unsigned int expected - Некорректное присваивание свойства: ожидается значение типа "unsigned int" + Некорректное присваивание свойства: ожидается значение типа «unsigned int» Invalid property assignment: int expected - Некорректное присваивание свойства: ожидается значение типа "int" + Некорректное присваивание свойства: ожидается значение типа «int» Invalid property assignment: number expected @@ -1422,31 +1438,31 @@ to Invalid property assignment: color expected - Некорректное присваивание свойства: ожидается значение типа "color" + Некорректное присваивание свойства: ожидается значение типа «color» Invalid property assignment: date expected - Некорректное присваивание свойства: ожидается значение типа "date" + Некорректное присваивание свойства: ожидается значение типа «date» Invalid property assignment: time expected - Некорректное присваивание свойства: ожидается значение типа "time" + Некорректное присваивание свойства: ожидается значение типа «time» Invalid property assignment: datetime expected - Некорректное присваивание свойства: ожидается значение типа "datetime" + Некорректное присваивание свойства: ожидается значение типа «datetime» Invalid property assignment: point expected - Некорректное присваивание свойства: ожидается значение типа "point" + Некорректное присваивание свойства: ожидается значение типа «point» Invalid property assignment: size expected - Некорректное присваивание свойства: ожидается значение типа "size" + Некорректное присваивание свойства: ожидается значение типа «size» Invalid property assignment: rect expected - Некорректное присваивание свойства: ожидается значение типа "rect" + Некорректное присваивание свойства: ожидается значение типа «rect» Invalid property assignment: boolean expected @@ -1454,11 +1470,11 @@ to Invalid property assignment: 3D vector expected - Некорректное присваивание свойства: ожидается значение типа "трёхмерный вектор" + Некорректное присваивание свойства: ожидается значение типа «трёхмерный вектор» Invalid property assignment: unsupported type "%1" - Некорректное присваивание свойства: неподдерживаемый тип "%1" + Некорректное присваивание свойства: неподдерживаемый тип «%1» Element is not creatable. @@ -1466,11 +1482,11 @@ to Component elements may not contain properties other than id - Элементы Component не могут содержать свойств кроме id + Элементы Component не могут содержать свойств кроме id Invalid component id specification - Некорректная спецификация id компонента + Некорректная спецификация id компонента id is not unique @@ -1478,60 +1494,68 @@ to Invalid component body specification - Некорректная спецификация тела компонента + Некорректная спецификация тела компонента Component objects cannot declare new properties. - Объекты Component не могут объявлять новые свойства. + Объекты Component не могут объявлять новые свойства. Component objects cannot declare new signals. - Объекты Component не могут объявлять новые сигналы. + Объекты Component не могут объявлять новые сигналы. Component objects cannot declare new functions. - Объекты Component не могут объявлять новые функции. + Объекты Component не могут объявлять новые функции. Cannot create empty component specification - Невозможно создать пустую спецификацю компонента + Невозможно создать пустую спецификацю компонента + + + "%1.%2" is not available in %3 %4.%5. + «%1.%2» не доступно в %3 %4.%5. + + + "%1.%2" is not available due to component versioning. + «%1.%2» не доступно из-за версии компоненты. Incorrectly specified signal assignment - Неверно указано назначение сигнала + Неверно указано назначение сигнала Cannot assign a value to a signal (expecting a script to be run) - Невозможно назначить значение сигналу (сценарий должен быть запущен) + Невозможно назначить значение сигналу (сценарий должен быть запущен) Empty signal assignment - Пустое назначение сигнала + Пустое назначение сигнала Empty property assignment - Пустое назначение свойства + Пустое назначение свойства Attached properties cannot be used here здесь - в данном контексте? - Прикреплённые свойства не могут быть использованы здесь + Прикреплённые свойства не могут быть использованы здесь Non-existent attached object - Несуществующий прикреплённый объект + Несуществующий прикреплённый объект Invalid attached object assignment - Некорректное назначение прикреплённого объекта + Некорректное назначение прикреплённого объекта Cannot assign to non-existent default property - Невозможно назначить несуществующему свойству по умолчанию + Невозможно назначить несуществующему свойству по умолчанию Cannot assign to non-existent property "%1" - Невозможно назначить несуществующему свойству "%1" + Невозможно назначить несуществующему свойству «%1» Invalid use of namespace @@ -1539,23 +1563,23 @@ to Not an attached property name - Не является именем привязанного свойства + Не является именем привязанного свойства Invalid use of id property - Некорректное использование свойства id + Некорректное использование свойства id Property has already been assigned a value - Свойству уже назначено значение + Свойству уже назначено значение Invalid grouped property access - Некорректный доступ к сгруппированному свойству + Некорректный доступ к сгруппированному свойству Cannot assign a value directly to a grouped property - Невозможно присвоить значение непосредственно сгруппированному свойству + Невозможно присвоить значение непосредственно сгруппированному свойству Invalid property use @@ -1563,55 +1587,55 @@ to Property assignment expected - Ожидается назначение свойства + Ожидается назначение свойства Single property assignment expected - Ожидается одиночное назначение свойства + Ожидается одиночное назначение свойства Unexpected object assignment - Неожиданное назначение объекта + Неожиданное назначение объекта Cannot assign object to list - Невозможно назначить объект списку + Невозможно назначить объект списку Can only assign one binding to lists - Можно назначить только одну связь для списка + Можно назначить только одну связь для списка Cannot assign primitives to lists - Невозможно назначить примитивы списку + Невозможно назначить примитивы списку Cannot assign multiple values to a script property - Невозможно назначить множественное значение свойству сценария + Невозможно назначить множественное значение свойству сценария Invalid property assignment: script expected - Некорректное присваивание свойства: ожидается сценарий + Некорректное присваивание свойства: ожидается сценарий Cannot assign multiple values to a singular property - Невозможно присвоить множество значений свойству, принимающему только одно + Невозможно присвоить множество значений свойству, принимающему только одно Cannot assign object to property - Невозможно назначить объектсвойству + Невозможно назначить объектсвойству "%1" cannot operate on "%2" - "%1" не может воздействовать на "%2" + «%1» не может воздействовать на «%2» Duplicate default property - Дублирование свойства по умолчанию + Дублирование свойства по умолчанию Duplicate property name - Дублирование названия свойства + Дублирование названия свойства Property names cannot begin with an upper case letter @@ -1623,7 +1647,7 @@ to Duplicate signal name - Дублирование названия сигнала + Дублирование названия сигнала Signal names cannot begin with an upper case letter @@ -1635,7 +1659,7 @@ to Duplicate method name - Дублирование название метода + Дублирование название метода Method names cannot begin with an upper case letter @@ -1647,11 +1671,11 @@ to Property value set multiple times - Значение свойства задано несколько раз + Значение свойства задано несколько раз Invalid property nesting - Некорректное вложенность свойств + Некорректное вложенность свойств Cannot override FINAL property @@ -1679,23 +1703,23 @@ to ID illegally masks global JavaScript property - Идентификатор неверно маскирует глобальное свойство JavaScript + Идентификатор неверно маскирует глобальное свойство JavaScript No property alias location - Отсутствует размещение псевдонима свойства + Отсутствует размещение псевдонима свойства Invalid alias location - Некорректное размещение псевдонима + Некорректное размещение псевдонима Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property> - Некорректная ссылка на псевдоним. Ссылка на псевдоним должна быть указана, как <id>, <id>.<свойство> или <id>.<свойство значения>.<свойство> + Некорректная ссылка на псевдоним. Ссылка на псевдоним должна быть указана, как <id>, <id>.<свойство> или <id>.<свойство значения>.<свойство> Alias property exceeds alias bounds - Свойство псевдонима выходит за границы + Свойство псевдонима выходит за границы Invalid alias reference. An alias reference must be specified as <id> or <id>.<property> @@ -1703,7 +1727,7 @@ to Invalid alias reference. Unable to find id "%1" - Некорректная ссылка на псевдоним. Не удалось найти id "%1" + Некорректная ссылка на псевдоним. Не удалось найти id «%1» @@ -1712,12 +1736,16 @@ to Invalid empty URL Пустой адрес URL + + createObject: value is not an object + createObject: значение не является объектом + QDeclarativeConnections Cannot assign to non-existent property "%1" - Невозможно назначить несуществующему свойству "%1" + Невозможно назначить несуществующему свойству «%1» Connections: nested objects not allowed @@ -1774,35 +1802,35 @@ to QDeclarativeImportDatabase cannot load module "%1": File name case mismatch for "%2" - невозможно загрузить модуль "%1": Регистр имени файла не соответствует "%2" + невозможно загрузить модуль «%1»: Регистр имени файла не соответствует «%2» module "%1" definition "%2" not readable - невозможно прочитать определение "%2" модуля "%1" + невозможно прочитать определение «%2» модуля «%1» plugin cannot be loaded for module "%1": %2 - модуль не может быть загружен для подмодуля "%1": %2 + не удалось загрузить плагин для модуля «%1»: %2 module "%1" plugin "%2" not found - подмодуль "%1" модуля "%2" не найден + модуль «%1» плагина «%2» не найден module "%1" version %2.%3 is not installed - модуль "%1" версии %2.%3 не установлен + модуль «%1» версии %2.%3 не установлен module "%1" is not installed - модуль "%1" не установлен + модуль «%1» не установлен "%1": no such directory - "%1": каталог не существует + «%1»: каталог не существует import "%1" has no qmldir and no namespace - каталог "%1" не содержит ни qmldir, ни namespace + каталог «%1» не содержит ни qmldir, ни namespace - %1 is not a namespace @@ -1834,21 +1862,32 @@ to File name case mismatch for "%2" - Регистр имени файла не соответствует "%2" + Регистр имени файла не соответствует «%2» QDeclarativeKeyNavigationAttached KeyNavigation is only available via attached properties - KeyNavigation доступна только через прикреплённые свойства + KeyNavigation доступна только через прикреплённые свойства QDeclarativeKeysAttached Keys is only available via attached properties - Keys доступны только через прикреплённые свойства + Keys доступны только через прикреплённые свойства + + + + QDeclarativeLayoutMirroringAttached + + LayoutDirection attached property only works with Items + Подключённое свойство LayoutDirection работает только с элементами + + + LayoutMirroring is only available via attached properties + LayoutMirroring доступно только через подключаемые свойства @@ -1887,7 +1926,7 @@ to ListElement: cannot use reserved "id" property - ListElement: невозможно использовать зарезервированное свойство "id" + ListElement: невозможно использовать зарезервированное свойство «id» ListElement: cannot use script for property value @@ -1895,7 +1934,7 @@ to ListModel: undefined property '%1' - ListModel: неопределённое свойство "%1" + ListModel: неопределённое свойство «%1» @@ -1971,7 +2010,7 @@ to Invalid regular expression flag '%0' - Некорректный флаг "%0" в регулярном выражении + Некорректный флаг «%0» в регулярном выражении Unterminated regular expression backslash sequence @@ -1987,15 +2026,15 @@ to Unexpected token `%1' - Неожиданный символ "%1" + Неожиданный символ «%1» Expected token `%1' - Ожидается символ "%1" + Ожидается символ «%1» Property value set multiple times - Значение свойства установлено несколько раз + Значение свойства установлено несколько раз Expected type name @@ -2003,11 +2042,11 @@ to Invalid import qualifier ID - Некорректный ID спецификатора импорта + Некорректный ID спецификатора импорта Reserved name "Qt" cannot be used as an qualifier - Зарезервированное имя "Qt" не может быть использовано в качестве спецификатора + Зарезервированное имя «Qt» не может быть использовано в качестве спецификатора Script import qualifiers must be unique. @@ -2019,7 +2058,7 @@ to Library import requires a version - Импорт библиотеки требует версию + Импорт библиотеки требует версию Expected parameter type @@ -2039,7 +2078,7 @@ to Readonly not yet supported - Readonly ещё не поддерживается + Readonly ещё не поддерживается JavaScript declaration outside Script element @@ -2079,26 +2118,26 @@ to QDeclarativePropertyChanges PropertyChanges does not support creating state-specific objects. - PropertyChanges не поддерживают создание объектов, зависимых от состояния. + PropertyChanges не поддерживают создание объектов, зависимых от состояния. Cannot assign to non-existent property "%1" - Невозможно назначить несуществующему свойству "%1" + Невозможно назначить несуществующему свойству «%1» Cannot assign to read-only property "%1" - Невозможно назначить свойству только для чтения "%1" + Невозможно назначить свойству только для чтения «%1» QDeclarativeTextInput Could not load cursor delegate - Не удалось загрузить делегат курсора + Не удалось загрузить делегат курсора Could not instantiate cursor delegate - Не удалось инстанциировать делегат курсора + Не удалось инстанциировать делегат курсора @@ -2109,11 +2148,11 @@ to Type %1 unavailable - Тип "%1" недоступен + Тип «%1» недоступен Namespace %1 cannot be used as a type - Пространство имён "%1" не может быть использовано в качестве типа + Пространство имён «%1» не может быть использовано в качестве типа %1 %2 @@ -2124,46 +2163,46 @@ to QDeclarativeVME Unable to create object of type %1 - Невозможно создать объект типа "%1" + Невозможно создать объект типа «%1» Cannot assign value %1 to property %2 - Невозможно установить значение "%1" свойству "%2" + Невозможно присвоить значение «%1» свойству «%2» Cannot assign object type %1 with no default method - Невозможно назначить объект типа %1 без метода по умолчанию + Невозможно присвоить объект типа «%1» без метода по умолчанию Cannot connect mismatched signal/slot %1 %vs. %2 - Невозможно подключить отсутствующий сигнал/слот %1 к %2 + Невозможно подключить отсутствующий сигнал/слот %1 к %2 Cannot assign an object to signal property %1 - Невозможно назначить объект к свойству сигнала %1 + Невозможно назначить объект к свойству сигнала %1 Cannot assign object to list - Невозможно назначить объект списку + Невозможно назначить объект списку Cannot assign object to interface property - Невозможно назначить объект свойству интерфейса + Невозможно назначить объект свойству интерфейса Unable to create attached object - Не удалось создать вложенный объект + Не удалось создать вложенный объект Cannot set properties on %1 as it is null - Невозможно установить свойства для %1, так как он нулевой + Невозможно установить свойства для %1, так как он нулевой QDeclarativeVisualDataModel Delegate component must be Item type. - Компинент делегата должен быть типа Item. + Компонента делегата должен быть типа Item. @@ -2177,14 +2216,14 @@ to QDeclarativeXmlListModelRole An XmlRole query must not start with '/' - Запрос XmlRole не должен начинаться с '/' + Запрос XmlRole не должен начинаться с «/» QDeclarativeXmlRoleList An XmlListModel query must start with '/' or "//" - Запрос XmlListModel должен начинаться с '/' или "//" + Запрос XmlListModel должен начинаться с «/» или «//» @@ -2345,11 +2384,11 @@ to Dock - Прикрепить + Прикрепить Float - Открепить + Открепить @@ -2478,7 +2517,7 @@ to '%1' is write protected. Do you want to delete it anyway? - "%1" защищён от записи. + «%1» защищён от записи. Действительно желаете удалить? @@ -2553,7 +2592,7 @@ Please verify the correct directory name was given. Are sure you want to delete '%1'? - Вы действительно хотите удалить "%1"? + Вы действительно хотите удалить «%1»? Could not delete directory. @@ -2652,7 +2691,7 @@ Please verify the correct directory name was given. <b>The name "%1" can not be used.</b><p>Try using another name, with fewer characters or no punctuations marks. - <b>Имя "%1" не может быть использовано.</b><p>Попробуйте использовать имя меньшей длины и/или без символов пунктуации. + <b>Имя «%1» не может быть использовано.</b><p>Попробуйте использовать имя меньшей длины и/или без символов пунктуации. Name @@ -3339,15 +3378,15 @@ Please verify the correct directory name was given. QLibrary Plugin verification data mismatch in '%1' - Проверочная информация для модуля "%1" не совпадает + Проверочная информация для модуля «%1» не совпадает The plugin '%1' uses incompatible Qt library. (%2.%3.%4) [%5] - Модуль "%1" использует несоместимую библиотеку Qt. (%2.%3.%4) [%5] + Модуль «%1» использует несоместимую библиотеку Qt. (%2.%3.%4) [%5] The plugin '%1' uses incompatible Qt library. Expected build key "%2", got "%3" - Модуль "%1" использует несоместимую библиотеку Qt. Ожидается ключ "%2", но получен ключ "%3" + Модуль «%1» использует несоместимую библиотеку Qt. Ожидается ключ «%2», но получен ключ «%3» Unknown error @@ -3359,11 +3398,11 @@ Please verify the correct directory name was given. The file '%1' is not a valid Qt plugin. - Файл "%1" - не является корректным модулем Qt. + Файл «%1» - не является корректным модулем Qt. The plugin '%1' uses incompatible Qt library. (Cannot mix debug and release libraries.) - Модуль "%1" использует несоместимую библиотеку Qt. (Невозможно совместить релизные и отладочные библиотеки.) + Модуль «%1» использует несоместимую библиотеку Qt. (Невозможно совместить релизные и отладочные библиотеки.) Cannot load library %1: %2 @@ -3375,7 +3414,7 @@ Please verify the correct directory name was given. Cannot resolve symbol "%1" in %2: %3 - Невозможно разрешить символ "%1" в %2: %3 + Невозможно разрешить символ «%1» в %2: %3 @@ -3906,7 +3945,7 @@ Please verify the correct directory name was given. Protocol "%1" is unknown - Неизвестный протокол "%1" + Неизвестный протокол «%1» Network session error. @@ -3936,7 +3975,7 @@ Please verify the correct directory name was given. Roaming error или перемещения? - Ошибка роуминга + Ошибка роуминга Session aborted by user or system @@ -3964,7 +4003,7 @@ Please verify the correct directory name was given. Roaming was aborted or is not possible. - Роуминг прерван или невозможен. + Роуминг прерван или невозможен. @@ -4057,7 +4096,7 @@ Please verify the correct directory name was given. QODBCResult QODBCResult::reset: Unable to set 'SQL_CURSOR_STATIC' as statement attribute. Please check your ODBC driver configuration - QODBCResult::reset: Невозможно установить "SQL_CURSOR_STATIC" атрибутом выражение. Проверьте настройки драйвера ODBC + QODBCResult::reset: Невозможно установить «SQL_CURSOR_STATIC» атрибутом выражение. Проверьте настройки драйвера ODBC Unable to execute statement @@ -4096,11 +4135,11 @@ Please verify the correct directory name was given. QObject "%1" duplicates a previous role name and will be disabled. - "%1" повторяет имя предыдущей роли и не будет использовано. + «%1» повторяет имя предыдущей роли и не будет использовано. invalid query: "%1" - Некорректный запрос: "%1" + Некорректный запрос: «%1» PulseAudio Sound Server @@ -4440,7 +4479,7 @@ Please choose a different file name. The 'From' value cannot be greater than the 'To' value. - Значение "с" не может быть больше значения "по". + Значение «с» не может быть больше значения «по». A0 @@ -6187,15 +6226,15 @@ Please choose a different file name. Code input - + Ввод кода Multiple Candidate - + Несколько вариантов Previous Candidate - + Предыдущий вариант Hangul @@ -6285,23 +6324,23 @@ Please choose a different file name. Ctrl - Ctrl + Shift - Shift + Alt - Alt + Meta - Meta + + - + + F%1 @@ -6514,6 +6553,10 @@ Please choose a different file name. Ошибка создания сессии SSL: %1 + The peer certificate is blacklisted + Сертификат узла в чёрном списке + + Cannot provide a certificate with no key, %1 Невозможно предоставить сертификат без ключа, %1 @@ -6622,15 +6665,15 @@ Please choose a different file name. QStateMachine Missing initial state in compound state '%1' - Отсутствует исходное состояние в составном состоянии "%1" + Отсутствует исходное состояние в составном состоянии «%1» Missing default state in history state '%1' - Отсутствует состояние по умолчанию в историческом состоянии "%1" + Отсутствует состояние по умолчанию в историческом состоянии «%1» No common ancestor for targets and source of transition from state '%1' - Нет общего предка у источника и цели перехода из состояния "%1" + Нет общего предка у источника и цели перехода из состояния «%1» Unknown error @@ -7122,7 +7165,7 @@ Please choose a different file name. Choose File title for file button used in HTML forms - Обзор... + Выбрать файл No file selected @@ -7202,13 +7245,13 @@ Please choose a different file name. No Guesses Found No Guesses Found context menu item - Совпадений не найдено + Совпадений не найдено Ignore Ignore Spelling context menu item ?Пропускать - Пропустить + Пропустить Add To Dictionary @@ -7218,12 +7261,12 @@ Please choose a different file name. Search The Web Search The Web context menu item - Искать в Интернет + Искать в Интернет Look Up In Dictionary Look Up in Dictionary context menu item - Искать в словаре + Искать в словаре Open Link @@ -7234,7 +7277,7 @@ Please choose a different file name. Ignore Ignore Grammar context menu item ?Пропускать - Пропустить + Пропустить Spelling @@ -7244,12 +7287,12 @@ Please choose a different file name. Show Spelling and Grammar menu item title - Показать панель проверки правописания + Показать панель проверки правописания Hide Spelling and Grammar menu item title - Скрыть панель проверки правописания + Скрыть панель проверки правописания Check Spelling @@ -7374,22 +7417,22 @@ Please choose a different file name. Mute Button Media controller element - Кнопка "Отключить звук" + Кнопка «Отключить звук» Unmute Button Media controller element - Кнопка "Включить звук" + Кнопка «Включить звук» Play Button Media controller element - Кнопка "Воспроизведение" + Кнопка «Воспроизведение» Pause Button Media controller element - Кнопка "Пауза" + Кнопка «Пауза» Slider @@ -7404,12 +7447,12 @@ Please choose a different file name. Rewind Button Media controller element - Кнопка "Перемотка назад" + Кнопка «Перемотка назад» Return to Real-time Button Media controller element - Кнопка "Вернуть в реальное время" + Кнопка «Вернуть в реальное время» Elapsed Time @@ -7429,17 +7472,17 @@ Please choose a different file name. Fullscreen Button Media controller element - Кнопка "На весь экран" + Кнопка «На весь экран» Seek Forward Button Media controller element - Кнопка "Перемотка вперёд" + Кнопка «Перемотка вперёд» Seek Back Button Media controller element - Кнопка "Перемотка назад" + Кнопка «Перемотка назад» Audio element playback controls and status display @@ -7474,12 +7517,12 @@ Please choose a different file name. Movie time scrubber Media controller element - Перемотка + Перемотка Movie time scrubber thumb Media controller element - Позиция перемотки + Позиция перемотки Rewind movie @@ -7489,7 +7532,7 @@ Please choose a different file name. Return streaming movie to real-time Media controller element - Возвращает потоковое видео к воспроизведению в реальном времени + Возвращает потоковое видео к воспроизведению в реальном времени Current movie time @@ -7602,7 +7645,7 @@ Please choose a different file name. Commit - Передать + Подтвердить Done @@ -7806,11 +7849,11 @@ Please choose a different file name. Sequence ']]>' not allowed in content. - Последовательность "]]>" недопустима в содержимом. + Последовательность «]]>» недопустима в содержимом. Namespace prefix '%1' not declared - Префикс пространства имён "%1" не объявлен + Префикс пространства имён «%1» не объявлен Attribute redefined. @@ -7818,7 +7861,7 @@ Please choose a different file name. Unexpected character '%1' in public id literal. - Неожиданный символ "%1" в литерале открытого идентификатора. + Неожиданный символ «%1» в литерале открытого идентификатора. Invalid XML version string. @@ -7838,7 +7881,7 @@ Please choose a different file name. Standalone accepts only yes or no. - Псевдоатрибут "standalone" может принимать только значения "yes" или "no". + Псевдоатрибут «standalone» может принимать только значения «yes» или «no». Invalid attribute in XML declaration. @@ -7906,15 +7949,15 @@ Please choose a different file name. Reference to unparsed entity '%1'. - Ссылка на необработанный объект "%1". + Ссылка на необработанный объект «%1». Entity '%1' not declared. - Объект "%1" не объявлен. + Объект «%1» не объявлен. Reference to external entity '%1' in attribute value. - Ссылка на внешний объект "%1" в значении атрибута. + Ссылка на внешний объект «%1» в значении атрибута. Invalid character reference. @@ -7926,7 +7969,7 @@ Please choose a different file name. The standalone pseudo attribute must appear after the encoding. - Псевдоатрибут "standalone" должен находиться после указания кодировки. + Псевдоатрибут «standalone» должен находиться после указания кодировки. %1 is an invalid PUBLIC identifier. @@ -7953,7 +7996,7 @@ Please choose a different file name. The data of a processing instruction cannot contain the string %1 - Данные обрабатываемой инструкции не могут содержать строку "%1" + Данные обрабатываемой инструкции не могут содержать строку «%1» %1 is an invalid %2 @@ -7969,11 +8012,11 @@ Please choose a different file name. In the replacement string, %1 must be followed by at least one digit when not escaped. - В замещаемой строке "%1" должно сопровождаться как минимум одной цифрой, если неэкранировано. + В замещаемой строке «%1» должно сопровождаться как минимум одной цифрой, если неэкранировано. In the replacement string, %1 can only be used to escape itself or %2, not %3 - В замещаемой строке символ "%1" может использоваться только для экранирования самого себя или "%2", но не "%3" + В замещаемой строке символ «%1» может использоваться только для экранирования самого себя или «%2», но не «%3» %1 matches newline characters @@ -8165,7 +8208,7 @@ Please choose a different file name. At least one time component must appear after the %1-delimiter. - Как минимум одна компонента времени должна следовать за разделителем '%1'. + Как минимум одна компонента времени должна следовать за разделителем «%1». Dividing a value of type %1 by %2 (not-a-number) is not allowed. @@ -8289,7 +8332,7 @@ Please choose a different file name. %1 must be followed by %2 or %3, not at the end of the replacement string. - "%1" должно сопровождаться "%2" или "%3", но не в конце замещаемой строки. + «%1» должно сопровождаться «%2» или «%3», но не в конце замещаемой строки. %1 and %2 match the start and end of a line. @@ -8689,15 +8732,15 @@ Please choose a different file name. %1 has inheritance loop in its base type %2. - + У %1 зациклено наследование в его базовом типе %2. Circular inheritance of base type %1. - + Цикличное наследование базового типа %1. Circular inheritance of union %1. - + Цикличное наследование базового объединения %1. %1 is not allowed to derive from %2 by restriction as the latter defines it as final. @@ -8709,19 +8752,19 @@ Please choose a different file name. Base type of simple type %1 cannot be complex type %2. - + Базовым простого типа %1 не может быть сложный %2. Simple type %1 cannot have direct base type %2. - + У простого типа %1 %2 не может быть непосредственным базовым типом. Simple type %1 is not allowed to have base type %2. - + Недопустимо, чтобы простой тип %1 имел базовым %2. Simple type %1 can only have simple atomic type as base type. - + У простого типа %1 может быть только простой атомарный базовый тип. Simple type %1 cannot derive from %2 as the latter defines restriction as final. @@ -8729,11 +8772,11 @@ Please choose a different file name. Variety of item type of %1 must be either atomic or union. - + Виды типов элементов %1 должны быть или атомарными, или объединениями. Variety of member types of %1 must be atomic. - + Виды внутренних типов %1 должны быть атомарными. %1 is not allowed to derive from %2 by list as the latter defines it as final. @@ -8741,11 +8784,11 @@ Please choose a different file name. Simple type %1 is only allowed to have %2 facet. - + Простой тип %1 может иметь только фасет %2. Base type of simple type %1 must have variety of type list. - + Базовый тип простого типа %1 должен содержать какой-нибудь список. Base type of simple type %1 has defined derivation by restriction as final. @@ -8753,11 +8796,11 @@ Please choose a different file name. Item type of base type does not match item type of %1. - + Тип элемента базового типа не совпадает с типом элемента %1. Simple type %1 contains not allowed facet type %2. - + Простой тип %1 содержит недопустимый фасет типа %2. %1 is not allowed to derive from %2 by union as the latter defines it as final. @@ -8765,11 +8808,11 @@ Please choose a different file name. %1 is not allowed to have any facets. - + %1 не может имет никаких фасетов. Base type %1 of simple type %2 must have variety of union. - + Базовый тип %1 простого типа %2 должен содержать какое-то объединение. Base type %1 of simple type %2 is not allowed to have restriction in %3 attribute. @@ -8777,171 +8820,171 @@ Please choose a different file name. Member type %1 cannot be derived from member type %2 of %3's base type %4. - + Внутренний тип %1 не может быть производным от типа %2, определённого в базовом типе типа %3 - %4. Derivation method of %1 must be extension because the base type %2 is a simple type. - + Метод наследования %1 должен быть «расширение», так как базовый тип %2 является простым. Complex type %1 has duplicated element %2 in its content model. - + Сложный тип %1 имеет повторяющийся элемент %2 в своей модели содержимого. Complex type %1 has non-deterministic content. - + Сложный тип %1 имеет недетерминированное содержимое. Attributes of complex type %1 are not a valid extension of the attributes of base type %2: %3. - + Атрибуты сложного типа %1 неверно дополняют атрибуты базового типа %2: %3. Content model of complex type %1 is not a valid extension of content model of %2. - + Модель содержимого сложного типа %1 неверно дополняет модель содержимого %2. Complex type %1 must have simple content. - + Сложный тип %1 должен иметь простое содержимое. Complex type %1 must have the same simple type as its base class %2. - + Сложный тип %1 должен содержать такой же простой тип, как и его базовый класс %2. Complex type %1 cannot be derived from base type %2%3. - + Сложный тип %1 не может быть производным от %2%3. Attributes of complex type %1 are not a valid restriction from the attributes of base type %2: %3. - + Атрибуты сложного типа %1 не являются верным ограничением атрибутов базового типа %2: %3. Complex type %1 with simple content cannot be derived from complex base type %2. - + Сложный тип %1 с простым содержимым не может быть производным от сложного типа %2. Item type of simple type %1 cannot be a complex type. - + Простой тип %1 не может содержать элементов сложных типов. Member type of simple type %1 cannot be a complex type. - + Простой тип %1 не может определять сложные типы. %1 is not allowed to have a member type with the same name as itself. - + Не допустимо, чтобы %1 определял внутренний тип с таким же именем. %1 facet collides with %2 facet. - + Фасет %1 противоречит %2. %1 facet must have the same value as %2 facet of base type. - + Фасет %1 должен иметь такое же значение, как и фасет %2 базового типа. %1 facet must be equal or greater than %2 facet of base type. - + Фасет %1 должен быть не менее фасета %2 базового типа. %1 facet must be less than or equal to %2 facet of base type. - + Фасет %1 должен быть не более фасета %2 базового типа. %1 facet contains invalid regular expression - + Фасет %1 содержит неверное регулярное выражение Unknown notation %1 used in %2 facet. - + В фасете %2 используется неизвестное обозначение %1. %1 facet contains invalid value %2: %3. - + Фасет %1 содержит неверное значение %2: %3. %1 facet cannot be %2 or %3 if %4 facet of base type is %5. - + Фасет %1 не может быть %2 или %3, если фасет %4 базового типа равен %5. %1 facet cannot be %2 if %3 facet of base type is %4. - + Фасет %1 не может быть %2, если фасет %3 базового типа равен %4. %1 facet must be less than or equal to %2 facet. - + Фасет %1 должен быть не более фасета %2. %1 facet must be less than %2 facet of base type. - + Фасет %1 должен быть менее фасета %2 базового типа. %1 facet and %2 facet cannot appear together. - + Фасеты %1 и %2 не могут быть одновременно. %1 facet must be greater than %2 facet of base type. - + Фасет %1 должен быть более фасета %2 базового типа. %1 facet must be less than %2 facet. - + Фасет %1 должен быть менее фасета %2. %1 facet must be greater than or equal to %2 facet of base type. - + Фасет %1 должен быть не менее фасета %2 базового типа. Simple type contains not allowed facet %1. - + Простой тип содержит недопустимый фасет %1. %1, %2, %3, %4, %5 and %6 facets are not allowed when derived by list. - + Недопустимы фасеты %1, %2, %3, %4, %5 и %6 при наследовании списком. Only %1 and %2 facets are allowed when derived by union. - + При наследовании объединением доступны только фасеты %1 и %2. %1 contains %2 facet with invalid data: %3. - + %1 содержит фасет %2 с неверными данными: %3. Attribute group %1 contains attribute %2 twice. - + Группа атрибутов %1 содержит два атрибута %2. Attribute group %1 contains two different attributes that both have types derived from %2. - + Группа атрибутов %1 содержит два разных атрибута, производных от %2. Attribute group %1 contains attribute %2 that has value constraint but type that inherits from %3. - + Группа атрибутов %1 содержит атрибут %2, на значение которого наложено ограничение, но тип наследован от %3. Complex type %1 contains attribute %2 twice. - + Сложный тип %1 содержит два атрибута %2. Complex type %1 contains two different attributes that both have types derived from %2. - + Сложный тип %1 содержит два разных атрибута, производных от %2. Complex type %1 contains attribute %2 that has value constraint but type that inherits from %3. - + Сложный тип %1 содержит атрибут %2, на значение которого наложено ограничение, но тип наследован от %3. Element %1 is not allowed to have a value constraint if its base type is complex. - + Элементу %1 недопустимо иметь ограничение на значения, если у его базовый тип сложный. Element %1 is not allowed to have a value constraint if its type is derived from %2. - + Элементу %1 недопустимо иметь ограничение на значения, если его тип производный от %2. Value constraint of element %1 is not of elements type: %2. - + Ограничение значения элемента %1 не типа элемента: %2. Element %1 is not allowed to have substitution group affiliation as it is no global element. @@ -8953,7 +8996,7 @@ Please choose a different file name. Value constraint of attribute %1 is not of attributes type: %2. - + Ограничение значения атрибута %1 не типа атрибута: %2. Attribute %1 has value constraint but has type derived from %2. @@ -9369,179 +9412,179 @@ Please choose a different file name. String content does not match the length facet. - + Содержимое строки не соответствует фасету length. String content does not match the minLength facet. - + Содержимое строки не соответствует фасету minLength. String content does not match the maxLength facet. - + Содержимое строки не соответствует фасету maxLength. String content does not match pattern facet. - + Содержимое строки не соответствует фасету pattern. String content is not listed in the enumeration facet. - + Содержимое строки отсутствует в фасете enumeration. Signed integer content does not match the maxInclusive facet. - + Знаковое целое не соответствует фасету maxInclusive. Signed integer content does not match the maxExclusive facet. - + Знаковое целое не соответствует фасету maxExclusive. Signed integer content does not match the minInclusive facet. - + Знаковое целое не соответствует фасету minInclusive. Signed integer content does not match the minExclusive facet. - + Знаковое целое не соответствует фасету minExclusive. Signed integer content is not listed in the enumeration facet. - + Знаковое целое отсутствует в фасете enumeration. Signed integer content does not match pattern facet. - + Знаковое целое не соответствует фасету pattern. Signed integer content does not match in the totalDigits facet. - + Знаковое целое не соответствует фасету totalDigits. Unsigned integer content does not match the maxInclusive facet. - + Беззнаковое целое не соответствует фасету maxInclusive. Unsigned integer content does not match the maxExclusive facet. - + Беззнаковое целое не соответствует фасету maxExclusive. Unsigned integer content does not match the minInclusive facet. - + Беззнаковое целое не соответствует фасету minInclusive. Unsigned integer content does not match the minExclusive facet. - + Беззнаковое целое не соответствует фасету minExclusive. Unsigned integer content is not listed in the enumeration facet. - + Беззнаковое целое отсутствует в фасете enumeration. Unsigned integer content does not match pattern facet. - + Беззнаковое целое не соответствует фасету pattern. Unsigned integer content does not match in the totalDigits facet. - + Беззнаковое целое не соответствует фасету totalDigits. Double content does not match the maxInclusive facet. - + Действительное число не соответствует фасету maxInclusive. Double content does not match the maxExclusive facet. - + Действительное число не соответствует фасету maxExclusive. Double content does not match the minInclusive facet. - + Действительное число не соответствует фасету minInclusive. Double content does not match the minExclusive facet. - + Действительное число не соответствует фасету minExclusive. Double content is not listed in the enumeration facet. - + Действительное число отсутствует в фасете enumeration. Double content does not match pattern facet. - + Действительное число не соответствует фасету pattern. Decimal content does not match in the fractionDigits facet. - + Десятичное не соответствует фасету fractionDigits. Decimal content does not match in the totalDigits facet. - + Десятичное не соответствует фасету totalDigits. Date time content does not match the maxInclusive facet. - + Дата-время не соответствует фасету maxInclusive. Date time content does not match the maxExclusive facet. - + Дата-время не соответствует фасету maxExclusive. Date time content does not match the minInclusive facet. - + Дата-время не соответствует фасету minInclusive. Date time content does not match the minExclusive facet. - + Дата-время не соответствует фасету minExclusive. Date time content is not listed in the enumeration facet. - + Дата-время отсутствует в фасете enumeration. Date time content does not match pattern facet. - + Дата-время не соответствует фасету pattern. Duration content does not match the maxInclusive facet. - + Длительность не соответствует фасету maxInclusive. Duration content does not match the maxExclusive facet. - + Длительность не соответствует фасету maxExclusive. Duration content does not match the minInclusive facet. - + Длительность не соответствует фасету minInclusive. Duration content does not match the minExclusive facet. - + Длительность не соответствует фасету minExclusive. Duration content is not listed in the enumeration facet. - + Длительность отсутствует в фасете enumeration. Duration content does not match pattern facet. - + Длительность не соответствует фасету pattern. Boolean content does not match pattern facet. - + Булевое число не соответствует фасету pattern. Binary content does not match the length facet. - + Двоичные данные не соответствуют фасету length. Binary content does not match the minLength facet. - + Двоичные данные не соответствуют фасету minLength. Binary content does not match the maxLength facet. - + Двоичные данные не соответствуют фасету maxLength. Binary content is not listed in the enumeration facet. - + Двоичные данные отсутствуют в фасете enumeration. Invalid QName content: %1. @@ -9549,43 +9592,43 @@ Please choose a different file name. QName content is not listed in the enumeration facet. - + Содержимое QName отсутствует в фасете enumeration. QName content does not match pattern facet. - + Содержимое QName не соответствует фасету pattern. Notation content is not listed in the enumeration facet. - + Содержимое Notation не перечислено в фасете enumeration. List content does not match length facet. - + Список не соответствует фасету length. List content does not match minLength facet. - + Список не соответствует фасету minLength. List content does not match maxLength facet. - + Список не соответствует фасету maxLength. List content is not listed in the enumeration facet. - + Содержимое списка не перечислено в фасете enumeration. List content does not match pattern facet. - + Содержимое списка не соответствует фасету pattern. Union content is not listed in the enumeration facet. - + Объединение не перечислено в фасете enumeration. Union content does not match pattern facet. - + Объединение не соответствует фасету pattern. Data of type %1 are not allowed to be empty. @@ -9753,7 +9796,7 @@ Please choose a different file name. ID value '%1' is not unique. - Значение ID "%1" неуникально. + Значение ID «%1» не уникально. '%1' attribute contains invalid QName content: %2. -- cgit v0.12 From d6a8beb9b15dc6cc6fe5d546d81c953e7f68520b Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 19 Apr 2011 20:27:06 +0200 Subject: Fix compilation with symbian-armcc the case of the headers matter if you compile on linux Reviewed-by: Marius Storm-Olsen --- src/plugins/qmltooling/qmldbg_ost/qostdevice.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qmltooling/qmldbg_ost/qostdevice.h b/src/plugins/qmltooling/qmldbg_ost/qostdevice.h index ba1f443..e33cf2d 100644 --- a/src/plugins/qmltooling/qmldbg_ost/qostdevice.h +++ b/src/plugins/qmltooling/qmldbg_ost/qostdevice.h @@ -42,7 +42,7 @@ #ifndef QOSTDEVICE_H #define QOSTDEVICE_H -#include +#include QT_BEGIN_NAMESPACE -- cgit v0.12 From c6e6a35aeb8794d68a3ca0c4e27a3a1181c066b5 Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Wed, 20 Apr 2011 08:08:41 +1000 Subject: Make QMLViewer startup animation stop after a while Task-number: QTBUG-18621 --- src/declarative/graphicsitems/qdeclarativemousearea.cpp | 16 ++++++++++++++++ src/declarative/graphicsitems/qdeclarativemousearea_p.h | 3 +++ .../graphicsitems/qdeclarativemousearea_p_p.h | 17 +++++++++++++++++ tools/qml/startup/startup.qml | 2 +- 4 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/declarative/graphicsitems/qdeclarativemousearea.cpp b/src/declarative/graphicsitems/qdeclarativemousearea.cpp index da11b00..47d8f94 100644 --- a/src/declarative/graphicsitems/qdeclarativemousearea.cpp +++ b/src/declarative/graphicsitems/qdeclarativemousearea.cpp @@ -496,6 +496,9 @@ void QDeclarativeMouseArea::mousePressEvent(QGraphicsSceneMouseEvent *event) d->pressAndHoldTimer.start(PressAndHoldDelay, this); setKeepMouseGrab(d->stealMouse); event->setAccepted(setPressed(true)); + + if(!event->isAccepted() && d->forwardToList.count()) + d->forwardEvent(event); } } @@ -573,6 +576,9 @@ void QDeclarativeMouseArea::mouseMoveEvent(QGraphicsSceneMouseEvent *event) me.setX(d->lastPos.x()); me.setY(d->lastPos.y()); emit positionChanged(&me); + + if(!event->isAccepted() && d->forwardToList.count()) + d->forwardEvent(event); } @@ -594,6 +600,9 @@ void QDeclarativeMouseArea::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) if (s && s->mouseGrabberItem() == this) ungrabMouse(); setKeepMouseGrab(false); + + if(!event->isAccepted() && d->forwardToList.count()) + d->forwardEvent(event); } d->doubleClick = false; } @@ -959,4 +968,11 @@ QDeclarativeDrag *QDeclarativeMouseArea::drag() */ +QDeclarativeListProperty QDeclarativeMouseArea::forwardTo() +{ + Q_D(QDeclarativeMouseArea); + return d->forwardTo; +} + + QT_END_NAMESPACE diff --git a/src/declarative/graphicsitems/qdeclarativemousearea_p.h b/src/declarative/graphicsitems/qdeclarativemousearea_p.h index 985f27e..351d4de 100644 --- a/src/declarative/graphicsitems/qdeclarativemousearea_p.h +++ b/src/declarative/graphicsitems/qdeclarativemousearea_p.h @@ -130,6 +130,7 @@ class Q_AUTOTEST_EXPORT QDeclarativeMouseArea : public QDeclarativeItem Q_PROPERTY(bool hoverEnabled READ hoverEnabled WRITE setHoverEnabled NOTIFY hoverEnabledChanged) Q_PROPERTY(QDeclarativeDrag *drag READ drag CONSTANT) //### add flicking to QDeclarativeDrag or add a QDeclarativeFlick ??? Q_PROPERTY(bool preventStealing READ preventStealing WRITE setPreventStealing NOTIFY preventStealingChanged REVISION 1) + Q_PROPERTY(QDeclarativeListProperty forwardTo READ forwardTo); public: QDeclarativeMouseArea(QDeclarativeItem *parent=0); @@ -157,6 +158,8 @@ public: bool preventStealing() const; void setPreventStealing(bool prevent); + QDeclarativeListProperty forwardTo(); + Q_SIGNALS: void hoveredChanged(); void pressedChanged(); diff --git a/src/declarative/graphicsitems/qdeclarativemousearea_p_p.h b/src/declarative/graphicsitems/qdeclarativemousearea_p_p.h index 67694fb..7248c92 100644 --- a/src/declarative/graphicsitems/qdeclarativemousearea_p_p.h +++ b/src/declarative/graphicsitems/qdeclarativemousearea_p_p.h @@ -70,6 +70,8 @@ public: : absorb(true), hovered(false), pressed(false), longPress(false), moved(false), stealMouse(false), doubleClick(false), preventStealing(false), drag(0) { + Q_Q(QDeclarativeMouseArea); + forwardTo = QDeclarativeListProperty(q, forwardToList); } ~QDeclarativeMouseAreaPrivate(); @@ -89,6 +91,18 @@ public: lastModifiers = event->modifiers(); } + void forwardEvent(QGraphicsSceneMouseEvent* event) + { + Q_Q(QDeclarativeMouseArea); + for(int i=0; i < forwardToList.count(); i++){ + event->setPos(forwardToList[i]->mapFromScene(event->scenePos())); + forwardToList[i]->scene()->sendEvent(forwardToList[i], event); + if(event->isAccepted()) + break; + } + event->setPos(q->mapFromScene(event->scenePos())); + } + bool isPressAndHoldConnected() { Q_Q(QDeclarativeMouseArea); static int idx = QObjectPrivate::get(q)->signalIndex("pressAndHold(QDeclarativeMouseEvent*)"); @@ -121,6 +135,9 @@ public: Qt::MouseButtons lastButtons; Qt::KeyboardModifiers lastModifiers; QBasicTimer pressAndHoldTimer; + + QDeclarativeListProperty forwardTo; + QList forwardToList; }; QT_END_NAMESPACE diff --git a/tools/qml/startup/startup.qml b/tools/qml/startup/startup.qml index fae7401..a216ac6 100644 --- a/tools/qml/startup/startup.qml +++ b/tools/qml/startup/startup.qml @@ -90,7 +90,7 @@ Rectangle { NumberAnimation on rotation { from: 0 to: 360 - loops: NumberAnimation.Infinite + loops: 3 running: true duration: 2000 } -- cgit v0.12 From 7a9ed6a1983e318bfb14f0b2db41b3a4e1415529 Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Tue, 19 Apr 2011 11:38:06 +0200 Subject: QNetworkCookie: do not access date string out of bounds --- src/network/access/qnetworkcookie.cpp | 2 +- tests/auto/qnetworkcookie/tst_qnetworkcookie.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/network/access/qnetworkcookie.cpp b/src/network/access/qnetworkcookie.cpp index c2a6925..52eb345 100644 --- a/src/network/access/qnetworkcookie.cpp +++ b/src/network/access/qnetworkcookie.cpp @@ -737,7 +737,7 @@ static QDateTime parseDateString(const QByteArray &dateString) // 4 digit Year if (isNum && year == -1 - && dateString.length() >= at + 3) { + && dateString.length() > at + 3) { if (isNumber(dateString[at + 1]) && isNumber(dateString[at + 2]) && isNumber(dateString[at + 3])) { diff --git a/tests/auto/qnetworkcookie/tst_qnetworkcookie.cpp b/tests/auto/qnetworkcookie/tst_qnetworkcookie.cpp index 91dfe47..e0c477b 100644 --- a/tests/auto/qnetworkcookie/tst_qnetworkcookie.cpp +++ b/tests/auto/qnetworkcookie/tst_qnetworkcookie.cpp @@ -707,6 +707,7 @@ void tst_QNetworkCookie::parseMultipleCookies_data() cookie.setDomain("!@#$%^&*();:."); // the ';' is actually problematic, because it is a separator list = QList(); QTest::newRow("domain-non-alpha-numeric") << "NonAlphNumDomName=NonAlphNumDomValue; domain=!@#$%^&*()" << list; + QTest::newRow("expiration-3digit1") << "a=b; expires=123" << list; // used to ASSERT } void tst_QNetworkCookie::parseMultipleCookies() -- cgit v0.12 From be4d73861441bd39d946d71b93f7f6f0ab445b50 Mon Sep 17 00:00:00 2001 From: mread Date: Wed, 20 Apr 2011 10:02:16 +0100 Subject: Drift correction and better accuracy for repeating timers in Symbian Timers on Symbian were always firing at least 2ms late. This was partly due to a paranoid extra delay in Qt and the kernel being very cautious. For one shot timers this is not so bad although a bit too much. But for repeating timers, this can cause significant reductions in firing rate particularly for short period timers. The timer active object now corrects timer lateness by up to 4ms per event. This is enough to compensate for the kernel lateness without the possibility of wild corrections. Task-number: QTBUG-18549 Reviewed-by: iain --- src/corelib/kernel/qeventdispatcher_symbian.cpp | 27 ++++++++++++++++++++----- src/corelib/kernel/qeventdispatcher_symbian_p.h | 3 +++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/corelib/kernel/qeventdispatcher_symbian.cpp b/src/corelib/kernel/qeventdispatcher_symbian.cpp index 47dd558..84825af 100644 --- a/src/corelib/kernel/qeventdispatcher_symbian.cpp +++ b/src/corelib/kernel/qeventdispatcher_symbian.cpp @@ -210,8 +210,10 @@ void QWakeUpActiveObject::RunL() QTimerActiveObject::QTimerActiveObject(QEventDispatcherSymbian *dispatcher, SymbianTimerInfo *timerInfo) : QActiveObject((timerInfo->interval) ? TIMER_PRIORITY : NULLTIMER_PRIORITY , dispatcher), - m_timerInfo(timerInfo) + m_timerInfo(timerInfo), m_expectedTimeSinceLastEvent(0) { + // start the timeout timer to ensure initialisation + m_timeoutTimer.start(); } QTimerActiveObject::~QTimerActiveObject() @@ -255,10 +257,23 @@ void QTimerActiveObject::StartTimer() m_rTimer.After(iStatus, MAX_SYMBIAN_TIMEOUT_MS * 1000); m_timerInfo->msLeft -= MAX_SYMBIAN_TIMEOUT_MS; } else { - //HighRes gives the 1ms accuracy expected by Qt, the +1 is to ensure that - //"Timers will never time out earlier than the specified timeout value" - //condition is always met. - m_rTimer.HighRes(iStatus, (m_timerInfo->msLeft + 1) * 1000); + // this algorithm implements drift correction for repeating timers + // calculate how late we are for this event + int timeSinceLastEvent = m_timeoutTimer.restart(); + int overshoot = timeSinceLastEvent - m_expectedTimeSinceLastEvent; + if (overshoot > m_timerInfo->msLeft) { + // we skipped a whole timeout, restart from here + overshoot = 0; + } + // calculate when the next event should happen + int waitTime = m_timerInfo->msLeft - overshoot; + m_expectedTimeSinceLastEvent = waitTime; + // limit the actual ms wait time to avoid wild corrections + // this will cause the real event time to slowly drift back to the expected event time + // measurements show that Symbian timers always fire 1 or 2 ms late + const int limit = 4; + waitTime = qMax(m_timerInfo->msLeft - limit, waitTime); + m_rTimer.HighRes(iStatus, waitTime * 1000); m_timerInfo->msLeft = 0; } SetActive(); @@ -305,6 +320,8 @@ void QTimerActiveObject::Start() if (!m_rTimer.Handle()) { qt_symbian_throwIfError(m_rTimer.CreateLocal()); } + m_timeoutTimer.start(); + m_expectedTimeSinceLastEvent = 0; StartTimer(); } else { iStatus = KRequestPending; diff --git a/src/corelib/kernel/qeventdispatcher_symbian_p.h b/src/corelib/kernel/qeventdispatcher_symbian_p.h index b785aea..a31a446 100644 --- a/src/corelib/kernel/qeventdispatcher_symbian_p.h +++ b/src/corelib/kernel/qeventdispatcher_symbian_p.h @@ -63,6 +63,7 @@ #include #include #include +#include #include @@ -143,6 +144,8 @@ private: private: SymbianTimerInfo *m_timerInfo; + QElapsedTimer m_timeoutTimer; + int m_expectedTimeSinceLastEvent; RTimer m_rTimer; }; -- cgit v0.12 From 18c9fce91c8f8f25c613e1be9030c36ce5c7d671 Mon Sep 17 00:00:00 2001 From: "Darryl L. Miles" Date: Wed, 20 Apr 2011 12:39:09 +0200 Subject: fix unititialized value use when timestamping qconfig.h we may be creating the forwarding header for a not yet existing file, so the timestamp may be undefined. Task-number: QTBUG-15330 Merge-request: 1174 Reviewed-by: ossi --- bin/syncqt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/syncqt b/bin/syncqt index b8f1ee7..7e1f581 100755 --- a/bin/syncqt +++ b/bin/syncqt @@ -334,7 +334,9 @@ sub syncHeader { open HEADER, ">$header" || die "Could not open $header for writing!\n"; print HEADER "#include \"$iheader_out\"\n"; close HEADER; - utime(time, $ts, $header) or die "$iheader, $header"; + if(defined($ts)) { + utime(time, $ts, $header) or die "$iheader, $header"; + } return 1; } return 0; -- cgit v0.12 From 6567ba691332aa6f97ace22ca9a5e127a9881c60 Mon Sep 17 00:00:00 2001 From: Sami Merila Date: Wed, 20 Apr 2011 14:57:51 +0300 Subject: Build break fix for simulated QS60Style Recent changes in QS60Style (to support placeholder background texture) causes the simulated style not to build. The implementation for new method placeHolderTexture() is on the Symbian-specific sourcefile, which is omitted in the simulator builds. As a fix, move the implementation to the "generic" style source file qs60style.cpp, since the method does not contain any Symbian specific code. Task-number: QTBUG-18863 Reviewed-by: owolff --- src/gui/styles/qs60style.cpp | 11 +++++++++++ src/gui/styles/qs60style_s60.cpp | 11 ----------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/gui/styles/qs60style.cpp b/src/gui/styles/qs60style.cpp index f146075..9958316 100644 --- a/src/gui/styles/qs60style.cpp +++ b/src/gui/styles/qs60style.cpp @@ -965,6 +965,17 @@ bool QS60StylePrivate::isWidgetPressed(const QWidget *widget) return (widget && widget == m_pressedWidget); } +// Generates 1*1 white pixmap as a placeholder for real texture. +// The actual theme texture is drawn in qt_s60_fill_background(). +QPixmap QS60StylePrivate::placeHolderTexture() +{ + if (!m_placeHolderTexture) { + m_placeHolderTexture = new QPixmap(1,1); + m_placeHolderTexture->fill(Qt::green); + } + return *m_placeHolderTexture; +} + /*! \class QS60Style \brief The QS60Style class provides a look and feel suitable for applications on S60. diff --git a/src/gui/styles/qs60style_s60.cpp b/src/gui/styles/qs60style_s60.cpp index dc64872..7f19c35 100644 --- a/src/gui/styles/qs60style_s60.cpp +++ b/src/gui/styles/qs60style_s60.cpp @@ -1440,17 +1440,6 @@ QPixmap QS60StylePrivate::backgroundTexture(bool skipCreation) return *m_background; } -// Generates 1*1 white pixmap as a placeholder for real texture. -// The actual theme texture is drawn in qt_s60_fill_background(). -QPixmap QS60StylePrivate::placeHolderTexture() -{ - if (!m_placeHolderTexture) { - m_placeHolderTexture = new QPixmap(1,1); - m_placeHolderTexture->fill(Qt::white); - } - return *m_placeHolderTexture; -} - QSize QS60StylePrivate::screenSize() { return QSize(S60->screenWidthInPixels, S60->screenHeightInPixels); -- cgit v0.12 From e684cfbe8a873040f1e6b0f7fe4bae76a6c1c5de Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Wed, 20 Apr 2011 14:01:25 +0200 Subject: Fix Symbian/Linux compilation breakage in plugins/qmltooling use QIODevice header file instead of (wrongly capitablized) QIODevice.h Reviewed-by: Tom Sutcliffe Task-number: QTBUG-18869 --- src/plugins/qmltooling/qmldbg_ost/qostdevice.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qmltooling/qmldbg_ost/qostdevice.h b/src/plugins/qmltooling/qmldbg_ost/qostdevice.h index ba1f443..2c26ff7 100644 --- a/src/plugins/qmltooling/qmldbg_ost/qostdevice.h +++ b/src/plugins/qmltooling/qmldbg_ost/qostdevice.h @@ -42,7 +42,7 @@ #ifndef QOSTDEVICE_H #define QOSTDEVICE_H -#include +#include QT_BEGIN_NAMESPACE -- cgit v0.12 From 5184d55d434296710041812976656ed6825447ec Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Wed, 20 Apr 2011 14:16:03 +0200 Subject: QDeclarativeDebug: Fix endless loop for property with SCRITABLE false Trying to read a property marked as non-scriptable results in an endless loop in QDeclarativePropertyCache::create . Task-number: QTBUG-18758 Reviewed-by: Aaron Kennedy --- src/declarative/qml/qdeclarativeenginedebug.cpp | 12 +++++++++--- .../qdeclarativedebug/tst_qdeclarativedebug.cpp | 21 ++++++++++++++++++--- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/declarative/qml/qdeclarativeenginedebug.cpp b/src/declarative/qml/qdeclarativeenginedebug.cpp index 31fd516..b2a05c3 100644 --- a/src/declarative/qml/qdeclarativeenginedebug.cpp +++ b/src/declarative/qml/qdeclarativeenginedebug.cpp @@ -249,10 +249,16 @@ void QDeclarativeEngineDebugServer::buildObjectDump(QDataStream &message, return; } - message << (object->metaObject()->propertyCount() + fakeProperties.count()); + QList propertyIndexes; + for (int ii = 0; ii < object->metaObject()->propertyCount(); ++ii) { + if (object->metaObject()->property(ii).isScriptable()) + propertyIndexes << ii; + } + + message << propertyIndexes.size() + fakeProperties.count(); - for (int ii = 0; ii < object->metaObject()->propertyCount(); ++ii) - message << propertyData(object, ii); + for (int ii = 0; ii < propertyIndexes.size(); ++ii) + message << propertyData(object, propertyIndexes.at(ii)); for (int ii = 0; ii < fakeProperties.count(); ++ii) message << fakeProperties[ii]; diff --git a/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp b/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp index d01463e..69f9732 100644 --- a/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp +++ b/tests/auto/declarative/qdeclarativedebug/tst_qdeclarativedebug.cpp @@ -66,7 +66,6 @@ Q_DECLARE_METATYPE(QDeclarativeDebugWatch::State) - class tst_QDeclarativeDebug : public QObject { Q_OBJECT @@ -118,6 +117,18 @@ private slots: void setBindingInStates(); }; +class NonScriptProperty : public QObject { + Q_OBJECT + Q_PROPERTY(int nonScriptProp READ nonScriptProp WRITE setNonScriptProp NOTIFY nonScriptPropChanged SCRIPTABLE false) +public: + int nonScriptProp() const { return 0; } + void setNonScriptProp(int) {} +signals: + void nonScriptPropChanged(); +}; +QML_DECLARE_TYPE(NonScriptProperty) + + QDeclarativeDebugObjectReference tst_QDeclarativeDebug::findRootObject(int context, bool recursive) { QDeclarativeDebugEnginesQuery *q_engines = m_dbg->queryAvailableEngines(this); @@ -282,6 +293,7 @@ void tst_QDeclarativeDebug::compareProperties(const QDeclarativeDebugPropertyRef void tst_QDeclarativeDebug::initTestCase() { qRegisterMetaType(); + qmlRegisterType("Test", 1, 0, "NonScriptPropertyElement"); QTest::ignoreMessage(QtWarningMsg, "Qml debugging is enabled. Only use this in a safe environment!"); QDeclarativeDebugHelper::enableDebugging(); @@ -291,7 +303,8 @@ void tst_QDeclarativeDebug::initTestCase() QList qml; qml << "import QtQuick 1.0\n" - "Item {" + "import Test 1.0\n" + "Item {" "id: root\n" "width: 10; height: 20; scale: blueRect.scale;" "Rectangle { id: blueRect; width: 500; height: 600; color: \"blue\"; }" @@ -307,6 +320,8 @@ void tst_QDeclarativeDebug::initTestCase() "list[0] = blueRect;\n" "varObjList = list;\n" "}\n" + "NonScriptPropertyElement {\n" + "}\n" "}"; // add second component to test multiple root contexts @@ -725,7 +740,7 @@ void tst_QDeclarativeDebug::queryObject() // check source as defined in main() QDeclarativeDebugFileReference source = obj.source(); QCOMPARE(source.url(), QUrl::fromLocalFile("")); - QCOMPARE(source.lineNumber(), 2); + QCOMPARE(source.lineNumber(), 3); QCOMPARE(source.columnNumber(), 1); // generically test all properties, children and childrens' properties -- cgit v0.12 From 92062a9af1dea35b9bdd781ee087755168ac1e77 Mon Sep 17 00:00:00 2001 From: Kai Koehne Date: Wed, 20 Apr 2011 16:06:48 +0200 Subject: QDeclarativeDebug: Fix typo in warning Add missing space to make the warning align with the others. Fix is needed to let QtCreator detect the warning programatically. Reviewed-by: Tom Sutcliffe --- src/declarative/debugger/qdeclarativedebugserver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/declarative/debugger/qdeclarativedebugserver.cpp b/src/declarative/debugger/qdeclarativedebugserver.cpp index 18258f5..7fa5a62 100644 --- a/src/declarative/debugger/qdeclarativedebugserver.cpp +++ b/src/declarative/debugger/qdeclarativedebugserver.cpp @@ -202,7 +202,7 @@ QDeclarativeDebugServer *QDeclarativeDebugServer::instance() connection->setServer(server); connection->setPort(port, block); } else { - qWarning() << QString::fromAscii("QDeclarativeDebugServer: Ignoring\"-qmljsdebugger=%1\". " + qWarning() << QString::fromAscii("QDeclarativeDebugServer: Ignoring \"-qmljsdebugger=%1\". " "Remote debugger plugin has not been found.").arg(appD->qmljsDebugArgumentsString()); } -- cgit v0.12 From ba3e66c0ffc3fd202e6b1b68006db1964ef2a9a9 Mon Sep 17 00:00:00 2001 From: Park Shinjo Date: Wed, 20 Apr 2011 18:44:59 +0200 Subject: Add Korean translation Merge-request: 1021 Reviewed-by: ossi --- translations/assistant_ko.ts | 1551 +++++++ translations/designer_ko.ts | 5817 ++++++++++++++++++++++++ translations/linguist_ko.ts | 2500 +++++++++++ translations/qt_help_ko.ts | 318 ++ translations/qt_ko.ts | 9941 ++++++++++++++++++++++++++++++++++++++++++ translations/qtconfig_ko.ts | 745 ++++ translations/qvfb_ko.ts | 415 ++ 7 files changed, 21287 insertions(+) create mode 100644 translations/assistant_ko.ts create mode 100644 translations/designer_ko.ts create mode 100644 translations/linguist_ko.ts create mode 100644 translations/qt_help_ko.ts create mode 100644 translations/qt_ko.ts create mode 100644 translations/qtconfig_ko.ts create mode 100644 translations/qvfb_ko.ts diff --git a/translations/assistant_ko.ts b/translations/assistant_ko.ts new file mode 100644 index 0000000..1dbdf4f --- /dev/null +++ b/translations/assistant_ko.ts @@ -0,0 +1,1551 @@ + + + + + AboutDialog + + &Close + 닫기(&C) + + + + AboutLabel + + Warning + 경고 + + + Unable to launch external application. + + 외부 프로그램을 시작할 수 없습니다. + + + + OK + 확인 + + + + Assistant + + Error registering documentation file '%1': %2 + 문서 파일 '%1'을(를) 등록하는 중 오류 발생: %2 + + + Error: %1 + 오류: %1 + + + Could not register documentation file +%1 + +Reason: +%2 + 다음 문서 파일을 등록할 수 없음: +%1 + +이유: +%2 + + + Documentation successfully registered. + 문서를 성공적으로 등록하였습니다. + + + Could not unregister documentation file +%1 + +Reason: +%2 + 다음 문서 파일의 등록을 해제할 수 없음: +%1 + +이유: +%2 + + + Documentation successfully unregistered. + 문서 파일의 등록을 해제하였습니다. + + + Error reading collection file '%1': %2. + 모음집 파일 '%1'을(를) 읽는 중 오류 발생: %2. + + + Error creating collection file '%1': %2. + 모음집 파일 '%1'을(를) 만드는 중 오류 발생: %2. + + + Cannot load sqlite database driver! + SQLite 데이터베이스 드라이버를 불러올 수 없습니다! + + + + BookmarkDialog + + Add Bookmark + 책갈피 추가 + + + Bookmark: + 책갈피: + + + Add in Folder: + 추가할 폴더: + + + + + + + + + New Folder + 새 폴더 + + + Rename Folder + 폴더 이름 바꾸기 + + + + BookmarkItem + + New Folder + 새 폴더 + + + Untitled + 제목 없음 + + + + BookmarkManager + + Untitled + 제목 없음 + + + Remove + 삭제 + + + You are going to delete a Folder, this will also<br>remove it's content. Are you sure to continue? + 폴더를 삭제하면 내용도 제거됩니다.<br>계속 진행하시겠습니까? + + + Manage Bookmarks... + 책갈피 관리... + + + Add Bookmark... + 책갈피 추가... + + + Ctrl+D + Ctrl+D + + + Delete Folder + 폴더 삭제 + + + Rename Folder + 폴더 이름 바꾸기 + + + Show Bookmark + 책갈피 열기 + + + Show Bookmark in New Tab + 새 탭으로 책갈피 열기 + + + Delete Bookmark + 책갈피 삭제 + + + Rename Bookmark + 책갈피 이름 바꾸기 + + + + BookmarkManagerWidget + + Manage Bookmarks + 책갈피 관리 + + + Search: + 찾기: + + + Remove + 삭제 + + + Import and Backup + 가져오기 및 백업 + + + OK + 확인 + + + Import... + 가져오기... + + + Export... + 내보내기... + + + Open File + 열기 + + + Files (*.xbel) + 파일 (*.xbel) + + + Save File + 파일 저장 + + + Qt Assistant + Qt Assistant + + + Unable to save bookmarks. + 책갈피를 저장할 수 없습니다. + + + You are goingto delete a Folder, this will also<br> remove it's content. Are you sure to continue? + 폴더를 삭제하면 내용도 제거됩니다.<br>계속 진행하시겠습니까? + + + Delete Folder + 폴더 삭제 + + + Rename Folder + 폴더 이름 바꾸기 + + + Show Bookmark + 책갈피 열기 + + + Show Bookmark in New Tab + 새 탭으로 책갈피 열기 + + + Delete Bookmark + 책갈피 삭제 + + + Rename Bookmark + 책갈피 이름 바꾸기 + + + + BookmarkModel + + Name + 이름 + + + Address + 주소 + + + Bookmarks Menu + 책갈피 메뉴 + + + + BookmarkWidget + + Bookmarks + 책갈피 + + + Filter: + 필터: + + + Add + 추가 + + + Remove + 삭제 + + + + CentralWidget + + Add new page + 새 쪽 추가 + + + Close current page + 현재 쪽 닫기 + + + Print Document + 문서 인쇄 + + + unknown + 알 수 없음 + + + Add New Page + 새 쪽 추가 + + + Close This Page + 이 쪽 닫기 + + + Close Other Pages + 다른 쪽 닫기 + + + Add Bookmark for this Page... + 이 쪽을 책갈피에 추가... + + + Search + 찾기 + + + + CmdLineParser + + Usage: assistant [Options] + +-collectionFile file Uses the specified collection + file instead of the default one +-showUrl url Shows the document with the + url. +-enableRemoteControl Enables Assistant to be + remotely controlled. +-show widget Shows the specified dockwidget + which can be "contents", "index", + "bookmarks" or "search". +-activate widget Activates the specified dockwidget + which can be "contents", "index", + "bookmarks" or "search". +-hide widget Hides the specified dockwidget + which can be "contents", "index" + "bookmarks" or "search". +-register helpFile Registers the specified help file + (.qch) in the given collection + file. +-unregister helpFile Unregisters the specified help file + (.qch) from the give collection + file. +-setCurrentFilter filter Set the filter as the active filter. +-remove-search-index Removes the full text search index. +-rebuild-search-index Re-builds the full text search index (potentially slow). +-quiet Does not display any error or + status message. +-help Displays this help. + + 사용 방법: assistant [옵션] + +-collectionFile file 기본 모음집 파일 대신 + 지정한 모음집 파일을 사용합니다. +-showUrl url 'url'에 있는 문서를 엽니다. +-enableRemoteControl Assistant 원격 제어를 사용합니다. +-show widget 지정한 도킹 가능한 위젯을 표시합니다. + 사용 가능한 값: "contents", "index", + "bookmarks" 및 "search". +-activate widget 지정한 도킹 가능한 위젯을 활성화합니다. + 사용 가능한 값: "contents", "index", + "bookmarks" 및 "search". +-hide widget 지정한 도킹 가능한 위젯을 숨깁니다. + 사용 가능한 값: "contents", "index" + "bookmarks" 및 "search". +-register helpFile 지정한 모음집 파일에 + 지정한 도움말 파일 (.qch)을 + 등록합니다. +-unregister helpFile 지정한 모음집 파일에서 + 지정한 도움말 파일 (.qch)의 + 등록을 해제합니다. +-setCurrentFilter filter 지정한 필터를 활성 필터로 지정합니다. +-remove-search-index 전문 검색 인덱스를 삭제합니다. +-rebuild-search-index 전문 검색 인덱스를 다시 생성합니다 (느릴 수도 있음). +-quiet 오류 및 상태 메시지를 + 표시하지 않습니다. +-help 이 도움말을 표시합니다. + + + + Unknown option: %1 + 알 수 없는 옵션: %1 + + + The collection file '%1' does not exist. + 모음집 파일 '%1'이(가) 존재하지 않습니다. + + + Missing collection file. + 모음집 파일이 존재하지 않습니다. + + + Invalid URL '%1'. + 잘못된 URL '%1'. + + + Missing URL. + URL이 존재하지 않습니다. + + + Unknown widget: %1 + 알 수 없는 위젯: %1 + + + Missing widget. + 위젯이 존재하지 않습니다. + + + The Qt help file '%1' does not exist. + Qt 도움말 파일 '%1'이(가) 존재하지 않습니다. + + + Missing help file. + 도움말 파일이 없습니다. + + + Missing filter argument. + 필터 인자가 없습니다. + + + Error + 오류 + + + Notice + 알림 + + + + ContentWindow + + Open Link + 링크 열기 + + + Open Link in New Tab + 새 탭으로 링크 열기 + + + + ConversionWizard + + Help Conversion Wizard + 도움말 변환 마법사 + + + Converting %1... + %1 변환 중... + + + Writing help collection file... + 도움말 모음집 파일에 쓰는 중... + + + Done. + 완료. + + + + FilesPage + + Form + + + + Files: + 파일: + + + Remove + 삭제 + + + Remove All + 모두 삭제 + + + Unreferenced Files + 참조되지 않은 파일 + + + Remove files which are neither referenced by a keyword nor by the TOC. + 키워드나 목차에서 참조하지 않는 파일을 삭제합니다. + + + <p><b>Warning:</b> When removing images or stylesheets, be aware that those files are not directly referenced by the .adp or .dcf file.</p> + <p><b>경고:</b> 그림이나 스타일 시트를 삭제한다면, .adp 파일이나 .dcf 파일에서 직접 참조하는지 여부를 확인하십시오.</p> + + + + FilterNameDialogClass + + Add Filter Name + 필터 이름 추가 + + + Filter Name: + 필터 이름: + + + + FilterPage + + Form + + + + Filter attributes for current documentation (comma separated list): + 현재 문서의 필터 속성 (쉼표로 구분된 목록): + + + Custom Filters + 사용자 정의 필터 + + + 1 + 1 + + + 2 + 2 + + + Add + 추가 + + + Remove + 삭제 + + + Filter Settings + 필터 설정 + + + Specify the filter attributes for the documentation. If filter attributes are used, also define a custom filter for it. Both the filter attributes and the custom filters are optional. + 문서의 필터 속성을 지정합니다. 필터 속성이 사용된다면 연관된 사용자 정의 필터도 정의해야 합니다. 필터 속성과 사용자 정의 필터는 선택 사항입니다. + + + Filter Name + 필터 이름 + + + Filter Attributes + 필터 속성 + + + The custom filter '%1' is defined multiple times. + 사용자 정의 필터 '%1'이(가) 여러 번 정의되었습니다. + + + The attributes for custom filter '%1' are defined multiple times. + 사용자 정의 필터의 속성 '%1'이(가) 여러 번 정의되었습니다. + + + unfiltered + list of available documentation + 필터되지 않음 + + + + FindWidget + + Previous + 이전 + + + Next + 다음 + + + Case Sensitive + 대소문자 구분 + + + <img src=":/trolltech/assistant/images/wrap.png">&nbsp;Search wrapped + <img src=":/trolltech/assistant/images/wrap.png">&nbsp;검색 다시 시작됨 + + + + FinishPage + + Converting File + 파일 변환 중 + + + Creating the new Qt help files from the old ADP file. + 이전 ADP 파일에서 새 Qt 도움말 파일을 만들고 있습니다. + + + + FontPanel + + Font + 글꼴 + + + &Writing system + 문자 체계(&W) + + + &Family + 글꼴 종류(&F) + + + &Style + 스타일(&S) + + + &Point size + 글꼴 크기(&P) + + + + GeneralPage + + Form + + + + Namespace: + 네임스페이스: + + + Virtual Folder: + 가상 폴더: + + + General Settings + 일반 설정 + + + Specify the namespace and the virtual folder for the documentation. + 문서의 네임스페이스와 가상 폴더를 설정합니다. + + + Namespace Error + 네임스페이스 오류 + + + The namespace contains some invalid characters. + 네임스페이스 이름에 올바르지 않은 문자가 포함되어 있습니다. + + + Virtual Folder Error + 가상 폴더 에러 + + + The virtual folder contains some invalid characters. + 가상 폴더 이름에 올바르지 않은 문자가 포함되어 있습니다. + + + + HelpEngineWrapper + + Unfiltered + 필터되지 않음 + + + + HelpGenerator + + Warning: %1 + 경고: %1 + + + + HelpViewer + + <title>about:blank</title> + <title>about:blank</title> + + + <title>Error 404...</title><div align="center"><br><br><h1>The page could not be found</h1><br><h3>'%1'</h3></div> + <title>404 오류...</title><div align="center"><br><br><h1>페이지를 찾을 수 없음</h1><br><h3>'%1'</h3></div> + + + Copy &Link Location + 링크 주소 복사(&L) + + + Open Link in New Tab Ctrl+LMB + 새 탭으로 링크 열기 Ctrl+LMB + + + Open Link in New Tab + 새 탭으로 링크 열기 + + + + HelpWindow + + <center><b>Wizard Assistant</b></center> + <center><b>마법사 도우미</b></center> + + + + IdentifierPage + + Form + + + + Create identifiers + 식별자 만들기 + + + Global prefix: + 전역 접두사: + + + Inherit prefix from file names + 파일 이름에서 접두사 상속받기 + + + Identifiers + 식별자 + + + This page allows you to create identifiers from the keywords found in the .adp or .dcf file. + 이 페이지에서는 .adp 및 .dcf 파일에서 찾은 키워드에서 식별자를 만들 수 있습니다. + + + + IndexWindow + + &Look for: + 찾을 문자열(&L): + + + Open Link + 링크 열기 + + + Open Link in New Tab + 새 탭으로 링크 열기 + + + + InputPage + + Form + + + + File name: + 파일 이름: + + + ... + ... + + + Input File + 입력 파일 + + + Specify the .adp or .dcf file you want to convert to the new Qt help project format and/or collection format. + 새로운 Qt 도움말 프로젝트 및 모음집 형식으로 변환할 .adp나 .dcp 파일을 지정하십시오. + + + Open file + 파일 열기 + + + Qt Help Files (*.adp *.dcf) + Qt 도움말 파일 (*.adp *.dcf) + + + File Open Error + 파일 열기 오류 + + + The specified file could not be opened! + 지정한 파일을 열 수 없습니다! + + + File Parsing Error + 파일 처리 오류 + + + Parsing error in line %1! + %1번째 줄에서 처리 오류 발생! + + + + InstallDialog + + Install Documentation + 문서 설치 + + + Available Documentation: + 사용 가능한 문서: + + + Install + 설치 + + + Cancel + 취소 + + + Close + 닫기 + + + Installation Path: + 설치 경로: + + + ... + ... + + + Downloading documentation info... + 문서 정보 다운로드 중... + + + Download canceled. + 다운로드가 취소되었습니다. + + + Done. + 완료. + + + The file %1 already exists. Do you want to overwrite it? + 파일 %1이(가) 이미 존재합니다. 겹쳐 쓰시겠습니까? + + + Unable to save the file %1: %2. + 파일 %1을(를) 저장할 수 없음: %2. + + + Downloading %1... + %1 다운로드 중... + + + Download failed: %1. + 다운로드 실패: %1. + + + Documentation info file is corrupt! + 문서 정보 파일이 손상되었습니다! + + + Download failed: Downloaded file is corrupted. + 다운로드 실패: 다운로드 받은 파일이 손상되었습니다. + + + Installing documentation %1... + 문서 %1 설치 중... + + + Error while installing documentation: +%1 + 문서를 설치하는 중 오류 발생: +%1 + + + + MainWindow + + Index + 색인 + + + Contents + 내용 + + + Bookmarks + 책갈피 + + + Qt Assistant + Qt Assistant + + + Looking for Qt Documentation... + Qt 문서 찾는 중... + + + &File + 파일(&F) + + + New &Tab + 새 탭(&T) + + + Page Set&up... + 쪽 설정(&U)... + + + Print Preview... + 인쇄 미리 보기... + + + &Print... + 인쇄(&P)... + + + &Close Tab + 탭 닫기(&C) + + + &Quit + 끝내기(&Q) + + + CTRL+Q + CTRL+Q + + + &Edit + 편집(&E) + + + &Copy selected Text + 선택한 텍스트 복사(&C) + + + &Find in Text... + 텍스트에서 찾기(&F)... + + + &Find + 찾기(&F) + + + Find &Next + 다음 찾기(&N) + + + Find &Previous + 이전 찾기(&P) + + + Preferences... + 환경 설정... + + + &View + 보기(&V) + + + Zoom &in + 확대(&I) + + + Zoom &out + 축소(&O) + + + Normal &Size + 원래 크기(&S) + + + Ctrl+0 + Ctrl+0 + + + ALT+C + ALT+C + + + ALT+I + ALT+I + + + ALT+O + ALT+O + + + Search + 찾기 + + + ALT+S + ALT+S + + + &Go + 이동(&G) + + + &Home + 홈 페이지(&H) + + + ALT+Home + ALT+Home + + + &Back + 뒤로(&B) + + + &Forward + 앞으로(&F) + + + Sync with Table of Contents + 목차와 동기화 + + + Sync + 동기화 + + + Next Page + 다음 쪽 + + + Ctrl+Alt+Right + Ctrl+Alt+Right + + + Previous Page + 이전 쪽 + + + Ctrl+Alt+Left + Ctrl+Alt+Left + + + &Bookmarks + 책갈피(&B) + + + &Help + 도움말(&H) + + + About... + 정보... + + + Navigation Toolbar + 탐색 도구 모음 + + + &Window + 창(&W) + + + Zoom + 확대/축소 + + + Minimize + 최소화 + + + Ctrl+M + Ctrl+M + + + Toolbars + 도구 모음 + + + Filter Toolbar + 필터 도구 모음 + + + Filtered by: + 필터 기준: + + + Address Toolbar + 주소 도구 모음 + + + Address: + 주소: + + + Could not find the associated content item. + 연결된 내용을 찾을 수 없습니다. + + + <center><h3>%1</h3><p>Version %2</p></center><p>Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).</p> + <center><h3>%1</h3><p>버전 %2</p></center><p>저작권자 (C) 2010 Nokia Corporation and/or its subsidiary(-ies).</p> + + + About %1 + %1 정보 + + + Updating search index + 검색 인덱스 업데이트 중 + + + Could not register file '%1': %2 + 파일 '%1'을(를) 등록할 수 없음: %2 + + + + OutputPage + + Form + + + + Project file name: + 프로젝트 파일 이름: + + + Collection file name: + 모음집 파일 이름: + + + Output File Names + 출력 파일 이름 + + + Specify the file names for the output files. + 출력 파일의 이름을 지정합니다. + + + Convert... + 변환... + + + Qt Help Project File + Qt 도움말 프로젝트 파일 + + + Qt Help Collection Project File + Qt 도움말 모음집 프로젝트 파일 + + + The specified file %1 already exist. + +Do you want to remove it? + 지정한 파일 %1이(가) 이미 존재합니다. + +삭제하시겠습니까? + + + Remove + 삭제 + + + Cancel + 취소 + + + + PathPage + + Form + + + + File filters: + 파일 필터: + + + Documentation source file paths: + 문서 원본 파일 경로: + + + Add + 추가 + + + Remove + 삭제 + + + Source File Paths + 원본 파일 경로 + + + Specify the paths where the sources files are located. By default, all files in those directories matched by the file filter will be included. + 원본 파일이 있는 경로를 지정하십시오. 기본적으로 필터와 일치하는 디렉터리에 있는 모든 파일이 포함됩니다. + + + Source File Path + 원본 파일 경로 + + + + PreferencesDialog + + Add Documentation + 문서 추가 + + + Qt Compressed Help Files (*.qch) + 압축된 Qt 도움말 파일 (*.qch) + + + The namespace %1 is already registered! + 네임스페이스 %1이(가) 이미 등록되어 있습니다! + + + The specified file is not a valid Qt Help File! + 지정한 파일은 올바른 Qt 도움말 파일이 아닙니다! + + + Remove Documentation + 문서 삭제 + + + Some documents currently opened in Assistant reference the documentation you are attempting to remove. Removing the documentation will close those documents. + 삭제하려고 하는 문서 중 일부는 현재 Assistant에 열려 있습니다. 문서를 삭제하면 삭제한 문서를 닫을 것입니다. + + + Cancel + 취소 + + + OK + 확인 + + + Use custom settings + 사용자 정의 설정 사용 + + + + PreferencesDialogClass + + Preferences + 환경 설정 + + + Fonts + 글꼴 + + + Font settings: + 글꼴 설정: + + + Browser + 브라우저 + + + Application + 프로그램 + + + Filters + 필터 + + + Filter: + 필터: + + + Attributes: + 속성: + + + 1 + 1 + + + Add + 추가 + + + Remove + 삭제 + + + Documentation + 문서 + + + Registered Documentation: + 등록된 문서: + + + Add... + 추가... + + + Options + 옵션 + + + On help start: + 도움말을 시작할 때: + + + Show my home page + 내 홈 페이지 보이기 + + + Show a blank page + 빈 페이지 보이기 + + + Show my tabs from last session + 마지막 세션에서 연 탭 보이기 + + + Homepage + 홈 페이지 + + + Current Page + 현재 페이지 + + + Blank Page + 빈 페이지 + + + Restore to default + 기본값으로 복원 + + + + QCollectionGenerator + + Unknown token at line %1. + %1번째 줄에 알 수 없는 토큰이 있습니다. + + + Unknown token at line %1. Expected "QtHelpCollectionProject". + %1번째 줄에 알 수 없는 토큰이 있습니다. 예상한 토큰: "QtHelpCollectionProject". + + + Missing end tags. + 끝맺는 태그가 없습니다. + + + Missing input or output file for help file generation. + 도움말 파일을 생성하기 위한 입력 및 출력 파일이 없습니다. + + + Missing output file name. + 출력 파일 이름이 없습니다. + + + Qt Collection Generator version 1.0 (Qt %1) + + Qt 모음집 생성기 버전 1.0 (Qt %1) + + + + Missing collection config file. + 모음집 설정 파일이 없습니다. + + + +Usage: + +qcollectiongenerator <collection-config-file> [options] + + -o <collection-file> Generates a collection file + called <collection-file>. If + this option is not specified + a default name will be used. + -v Displays the version of + qcollectiongenerator. + + + +사용 방법: + +qcollectiongenerator <collection-config-file> [옵션] + + -o <collection-file> 모음집 파일 <collection-file>을 + 생성합니다. 이 옵션이 지정되지 + 않으면 기본 이름을 사용합니다. + -v qcollectiongenerator의 + 버전을 표시합니다. + + + + + Could not open %1. + + %1을(를) 열 수 없습니다. + + + + Reading collection config file... + + 모음집 설정 파일을 읽는 중... + + + + Collection config file error: %1 + + 모음집 설정 파일 오류: %1 + + + + Generating help for %1... + + %1의 도움말 생성 중... + + + + Creating collection file... + + 모음집 파일 생성 중... + + + + The file %1 cannot be overwritten. + + 파일 %1에 겹쳐 쓸 수 없습니다. + + + + Cannot open %1. + + %1을(를) 열 수 없습니다. + + + + Cannot open referenced image file %1. + + 참조하는 그림 파일 %1을(를) 열 수 없습니다. + + + + + QHelpGenerator + + Missing output file name. + 출력 파일 이름이 없습니다. + + + Qt Help Generator version 1.0 (Qt %1) + + Qt 도움말 생성기 버전 1.0 (Qt %1) + + + + Missing Qt help project file. + Qt 도움말 프로젝트 파일이 없습니다. + + + +Usage: + +qhelpgenerator <help-project-file> [options] + + -o <compressed-file> Generates a Qt compressed help + file called <compressed-file>. + If this option is not specified + a default name will be used. + -c Checks whether all links in HTML files + point to files in this help project. + -v Displays the version of + qhelpgenerator. + + + +사용 방법: + +qhelpgenerator <help-project-file> [옵션] + + -o <compressed-file> Qt 압축된 도움말 파일 + <compressed-file>을 생성합니다. + 이 옵션을 지정하지 않으면 + 기본 이름을 사용합니다. + -c HTML 파일에 있는 모든 링크가 + 이 프로젝트에 있는 파일을 + 가리키는지 확인합니다. + -v qhelpgenerator의 버전을 + 표시합니다. + + + + + Could not open %1. + + %1을(를) 열 수 없습니다. + + + + Could not create output directory: %1 + + 출력 디렉터리를 만들 수 없습니다: %1 + + + + + RemoteControl + + Debugging Remote Control + 원격 제어 디버그 + + + Received Command: %1 %2 + 받은 명령: %1 %2 + + + + SearchWidget + + &Copy + 복사(&C) + + + Copy &Link Location + 링크 주소 복사(&L) + + + Open Link in New Tab + 새 탭으로 링크 열기 + + + Select All + 모두 선택 + + + + TopicChooser + + Choose Topic + 주제 선택 + + + &Topics + 주제(&T) + + + &Display + 표시(&D) + + + &Close + 닫기(&C) + + + Choose a topic for <b>%1</b>: + <b>%1</b>의 주제를 선택하십시오: + + + diff --git a/translations/designer_ko.ts b/translations/designer_ko.ts new file mode 100644 index 0000000..b14273f --- /dev/null +++ b/translations/designer_ko.ts @@ -0,0 +1,5817 @@ + + + + + AbstractFindWidget + + &Previous + 이전 찾기(&P) + + + &Next + 다음 찾기(&N) + + + &Case sensitive + 대소문자 구분(&C) + + + Whole &words + 단어 단위로(&W) + + + <img src=":/trolltech/shared/images/wrap.png">&nbsp;Search wrapped + <img src=":/trolltech/shared/images/wrap.png">&nbsp;검색 다시 시작됨 + + + + AbstractItemEditor + + Selectable + 선택가능 + + + Editable + 편집가능 + + + DragEnabled + 드래그가능 + + + DropEnabled + 드롭가능 + + + UserCheckable + 사용자선택가능 + + + Enabled + 활성화됨 + + + Tristate + 삼중상태 + + + Unchecked + 선택안됨 + + + PartiallyChecked + 부분선택됨 + + + Checked + 선택됨 + + + + AddLinkDialog + + Insert Link + 링크 삽입 + + + Title: + 제목: + + + URL: + URL: + + + + AppFontDialog + + Additional Fonts + 추가 글꼴 + + + + AppFontManager + + '%1' is not a file. + '%1'은(는) 파일이 아닙니다. + + + The font file '%1' does not have read permissions. + 글꼴 파일 '%1'을(를) 읽을 수 있는 권한이 없습니다. + + + The font file '%1' is already loaded. + 글꼴 파일 '%1'을(를) 이미 불러왔습니다. + + + The font file '%1' could not be loaded. + 글꼴 파일 '%1'을(를) 불러올 수 없습니다. + + + '%1' is not a valid font id. + '%1'은(는) 올바른 글꼴 ID가 아닙니다. + + + There is no loaded font matching the id '%1'. + 불러온 글꼴 중 ID '%1'인 글꼴이 없습니다. + + + The font '%1' (%2) could not be unloaded. + 글꼴 '%1' (%2)을(를) 닫을 수 없습니다. + + + + AppFontWidget + + Fonts + 글꼴 + + + Add font files + 글꼴 파일 추가 + + + Remove current font file + 현재 글꼴 파일 삭제 + + + Remove all font files + 모든 글꼴 파일 삭제 + + + Add Font Files + 글꼴 파일 추가 + + + Font files (*.ttf) + 글꼴 파일 (*.ttf) + + + Error Adding Fonts + 글꼴 추가 오류 + + + Error Removing Fonts + 글꼴 삭제 오류 + + + Remove Fonts + 글꼴 삭제 + + + Would you like to remove all fonts? + 모든 글꼴을 삭제하시겠습니까? + + + + AppearanceOptionsWidget + + Form + + + + User Interface Mode + 사용자 인터페이스 모드 + + + + AssistantClient + + Unable to send request: Assistant is not responding. + 요청을 보낼 수 없음: Assistant가 응답하지 않습니다. + + + The binary '%1' does not exist. + 실행 파일 '%1'이(가) 존재하지 않습니다. + + + Unable to launch assistant (%1). + Assistant(%1)를 시작할 수 없습니다. + + + + BrushPropertyManager + + No brush + 브러시 없음 + + + Solid + 단색 + + + Dense 1 + 점무늬 1 + + + Dense 2 + 점무늬 2 + + + Dense 3 + 점무늬 3 + + + Dense 4 + 점무늬 4 + + + Dense 5 + 점무늬 5 + + + Dense 6 + 점무늬 6 + + + Dense 7 + 점무늬 7 + + + Horizontal + 수평선 + + + Vertical + 수직선 + + + Cross + 교차하는 가로 및 세로선 + + + Backward diagonal + 대각선 (오른쪽 아래로) + + + Forward diagonal + 대각선 (오른쪽 위로) + + + Crossing diagonal + 교차하는 대각선 + + + Style + 스타일 + + + Color + 색상 + + + [%1, %2] + [%1, %2] + + + + Command + + Add connection + 연결 추가 + + + Adjust connection + 연결 수정 + + + Delete connections + 연결 삭제 + + + Change source + 원본 변경 + + + Change target + 대상 변경 + + + Add '%1' to '%2' + Command description for adding buttons to a QButtonGroup + '%1'을(를) '%2'에 추가 + + + Morph %1/'%2' into %3 + MorphWidgetCommand description + %1/'%2'을(를) %3(으)로 변형 + + + Insert '%1' + '%1' 삽입 + + + Change Z-order of '%1' + '%1'의 Z 순서 변경 + + + Raise '%1' + '%1' 위로 올림 + + + Lower '%1' + '%1' 아래로 내림 + + + Delete '%1' + '%1' 삭제 + + + Reparent '%1' + '%1' 부모 변경 + + + Promote to custom widget + 사용자 정의 위젯으로 승격 + + + Demote from custom widget + 사용자 정의 위젯에서 승격 해제 + + + Lay out using grid + 격자형으로 배치 + + + Lay out vertically + 수직으로 배치 + + + Lay out horizontally + 수평으로 배치 + + + Break layout + 레이아웃 풀기 + + + Simplify Grid Layout + 격자 레이아웃 간단하게 하기 + + + Move Page + 쪽 이동 + + + Delete Page + 쪽 삭제 + + + Page + + + + Insert Page + 쪽 삽입 + + + Change Tab order + 탭 순서 변경 + + + Create Menu Bar + 메뉴 표시줄 생성 + + + Delete Menu Bar + 메뉴 표시줄 삭제 + + + Create Status Bar + 상태 표시줄 생성 + + + Delete Status Bar + 상태 표시줄 삭제 + + + Add Tool Bar + 도구 모음 추가 + + + Add Dock Window + 독 창 추가 + + + Adjust Size of '%1' + '%1'의 크기 조정 + + + Change Form Layout Item Geometry + 폼 레이아웃 항목 크기 변경 + + + Change Layout Item Geometry + 레이아웃 항목 크기 변경 + + + Delete Subwindow + 하위 창 삭제 + + + page + + + + Insert Subwindow + 하위 창 삽입 + + + subwindow + subwindow + + + Subwindow + 하위 창 + + + Change Table Contents + 표 내용 변경 + + + Change Tree Contents + 트리 내용 변경 + + + Add action + 동작 추가 + + + Remove action + 동작 삭제 + + + Add menu + 메뉴 추가 + + + Remove menu + 메뉴 삭제 + + + Create submenu + 하위 메뉴 생성 + + + Delete Tool Bar + 도구 모음 삭제 + + + Change layout of '%1' from %2 to %3 + '%1'의 레이아웃을 %2에서 %3(으)로 변경 + + + Set action text + 동작 텍스트 설정 + + + Insert action + 동작 삽입 + + + Move action + 동작 이동 + + + Change Title + 제목 변경 + + + Insert Menu + 메뉴 추가 + + + Changed '%1' of '%2' + '%2'의 '%1' 변경 + + + Changed '%1' of %n objects + + 객체 %n개의 '%1' 변경 + + + + Reset '%1' of '%2' + '%2'의 '%1' 초기화 + + + Reset '%1' of %n objects + + 객체 %n개의 '%1' 초기화 + + + + Add dynamic property '%1' to '%2' + 동적 속성 '%1'을(를) '%2'에 추가 + + + Add dynamic property '%1' to %n objects + + 동적 속성 %1을(를) 객체 %n개에 추가 + + + + Remove dynamic property '%1' from '%2' + 동적 속성 '%1'을(를) '%2'에서 삭제 + + + Remove dynamic property '%1' from %n objects + + 동적 속성 '%1'을(를) 객체 %n개에서 삭제 + + + + Change script + 스크립트 변경 + + + Change signals/slots + 시그널/슬롯 변경 + + + Change signal + 시그널 변경 + + + Change slot + 슬롯 변경 + + + Change signal-slot connection + 시그널-슬롯 연결 변경 + + + Change sender + 송신자 변경 + + + Change receiver + 수신자 변경 + + + Create button group + 단추 그룹 생성 + + + Break button group + 단추 그룹 풀기 + + + Break button group '%1' + 단추 그룹 '%1' 풀기 + + + Add buttons to group + 단추를 그룹에 추가 + + + Remove buttons from group + 단추를 그룹에서 삭제 + + + Remove '%1' from '%2' + Command description for removing buttons from a QButtonGroup + '%2'에서 '%1' 삭제 + + + + ConnectDialog + + Configure Connection + 연결 설정 + + + GroupBox + 그룹상자 + + + Edit... + 편집... + + + Show signals and slots inherited from QWidget + QWidget에서 상속받은 시그널과 슬롯 보이기 + + + + ConnectionDelegate + + <object> + <객체> + + + <signal> + <시그널> + + + <slot> + <슬롯> + + + + DPI_Chooser + + Standard (96 x 96) + Embedded device standard screen resolution + 표준 (96 x 96) + + + Greenphone (179 x 185) + Embedded device screen resolution + Greenphone (179 x 185) + + + High (192 x 192) + Embedded device high definition screen resolution + 고해상도 (192 x 192) + + + + Designer + + Unable to launch %1. + %1을(를) 실행할 수 없습니다. + + + %1 timed out. + %1의 시간이 초과되었습니다. + + + Custom Widgets + 사용자 정의 위젯 + + + Promoted Widgets + 승격된 위젯 + + + Qt Designer + Qt Designer + + + This file contains top level spacers.<br>They have <b>NOT</b> been saved into the form. + 이 파일에는 최상위 단계 스페이서가 포함되어 있습니다.<br>이들은 폼에 저장되지 <b>않았습니다</b>. + + + Perhaps you forgot to create a layout? + 레이아웃을 만들지 않았습니까? + + + Invalid UI file: The root element <ui> is missing. + 잘못된 UI 파일: 최상위 원소 <ui>가 없습니다. + + + An error has occurred while reading the UI file at line %1, column %2: %3 + UI 파일의 %1번째 줄, %2번째 칸을 읽는 중 오류가 발생하였습니다: %3 + + + This file cannot be read because it was created using %1. + 이 파일은 %1을(를) 사용하여 만들었기 때문에 읽을 수 없습니다. + + + This file was created using Designer from Qt-%1 and cannot be read. + 이 파일은 Qt %1의 Designer로 만들었기 때문에 읽을 수 없습니다. + + + The converted file could not be read. + 변환된 파일을 읽을 수 없습니다. + + + This file was created using Designer from Qt-%1 and will be converted to a new form by Qt Designer. + 이 파일은 Qt %1의 Designer로 만들었으며, Qt Designer에서 새로운 폼으로 변환할 것입니다. + + + The old form has not been touched, but you will have to save the form under a new name. + 이전 폼 파일은 변경되지 않았습니다. 새로운 폼을 저장하려면 다른 이름으로 저장하십시오. + + + This file was created using Designer from Qt-%1 and could not be read: +%2 + 이 파일은 Qt %1의 Designer로 만들어졌으며 읽을 수 없습니다: +%2 + + + Please run it through <b>uic3&nbsp;-convert</b> to convert it to Qt-4's ui format. + <b>uic3&nbsp;-convert</b> 명령을 실행하여 Qt 4의 UI 형식으로 변환하십시오. + + + This file cannot be read because the extra info extension failed to load. + 추가 정보 확장을 불러올 수 없으므로 이 파일을 읽을 수 없습니다. + + + + DesignerMetaEnum + + %1 is not a valid enumeration value of '%2'. + %1은(는) 열거형 '%2'의 올바른 값이 아닙니다. + + + '%1' could not be converted to an enumeration value of type '%2'. + '%1'을(를) 열거형 '%2'의 값으로 변환할 수 없습니다. + + + + DesignerMetaFlags + + '%1' could not be converted to a flag value of type '%2'. + '%1'을(를) 플래그 형식 '%2'의 값으로 변환할 수 없습니다. + + + + DeviceProfile + + '%1' is not a number. + Reading a number for an embedded device profile + '%1'은(는) 숫자가 아닙니다. + + + An invalid tag <%1> was encountered. + 잘못된 태그 <%1>이(가) 있습니다. + + + + DeviceProfileDialog + + &Family + 종류(&F) + + + &Point Size + 포인트 크기(&P) + + + Style + 스타일 + + + Device DPI + 장치 DPI + + + Name + 이름 + + + + DeviceSkin + + The image file '%1' could not be loaded. + 그림 파일 '%1'을(를) 불러올 수 없습니다. + + + The skin directory '%1' does not contain a configuration file. + 스킨 디렉터리 '%1'에 설정 파일이 없습니다. + + + The skin configuration file '%1' could not be opened. + 스킨 설정 파일 '%1'을(를) 열 수 없습니다. + + + The skin configuration file '%1' could not be read: %2 + 스킨 설정 파일 '%1'을(를) 읽을 수 없습니다: %2 + + + Syntax error: %1 + 문법 오류: %1 + + + The skin "up" image file '%1' does not exist. + 스킨 "up" 그림 파일 '%1'이(가) 존재하지 않습니다. + + + The skin "down" image file '%1' does not exist. + 스킨 "down" 그림 파일 '%1'이(가) 존재하지 않습니다. + + + The skin "closed" image file '%1' does not exist. + 스킨 "closed" 그림 파일 '%1'이(가) 존재하지 않습니다. + + + The skin cursor image file '%1' does not exist. + 스킨 커서 그림 파일 '%1'이(가) 존재하지 않습니다. + + + Syntax error in area definition: %1 + 영역 지정 문법 오류: %1 + + + Mismatch in number of areas, expected %1, got %2. + 영역 개수가 일치하지 않습니다: %1개를 예상하였지만 %2개 정의되었습니다. + + + + EmbeddedOptionsControl + + <html><table><tr><td><b>Font</b></td><td>%1, %2</td></tr><tr><td><b>Style</b></td><td>%3</td></tr><tr><td><b>Resolution</b></td><td>%4 x %5</td></tr></table></html> + Format embedded device profile description + <html><table><tr><td><b>글꼴</b></td><td>%1, %2</td></tr><tr><td><b>스타일</b></td><td>%3</td></tr><tr><td><b>해상도</b></td><td>%4 x %5</td></tr></table></html> + + + + EmbeddedOptionsPage + + Embedded Design + Tab in preferences dialog + 임베디드 디자인 + + + Device Profiles + EmbeddedOptionsControl group box" + 장치 프로필 + + + + FontPanel + + Font + 글꼴 + + + &Writing system + 문자 체계(&W) + + + &Family + 글꼴 종류(&F) + + + &Style + 스타일(&S) + + + &Point size + 포인트 크기(&P) + + + + FontPropertyManager + + PreferDefault + 기본값우선 + + + NoAntialias + 앤티에일리어싱없음 + + + PreferAntialias + 앤티에일리어싱선호 + + + Antialiasing + 앤티에일리어싱 + + + + FormBuilder + + Invalid stretch value for '%1': '%2' + Parsing layout stretch values +---------- +Parsing layout stretch values +---------- +Parsing layout stretch values + '%1'의 stretch 값이 잘못됨: '%2' + + + Invalid minimum size for '%1': '%2' + Parsing grid layout minimum size values +---------- +Parsing grid layout minimum size values +---------- +Parsing grid layout minimum size values + '%1'의 최소 크기가 잘못됨: '%2' + + + + FormEditorOptionsPage + + %1 % + Zoom percentage + %1 % + + + Preview Zoom + 크기 미리 보기 + + + Default Zoom + 기본 크기 + + + Forms + Tab in preferences dialog + + + + Default Grid + 기본 격자 + + + + FormLayoutRowDialog + + Add Form Layout Row + 폼 레이아웃 행 추가하기 + + + &Label text: + 레이블 텍스트(&L): + + + Field &type: + 필드 형식(&T): + + + &Field name: + 필드 이름(&F): + + + &Buddy: + 친구(&B): + + + &Row: + 행(&R): + + + Label &name: + 레이블 이름(&N): + + + + FormWindow + + Unexpected element <%1> + 예상하지 못한 원소 <%1> + + + Error while pasting clipboard contents at line %1, column %2: %3 + 클립보드 내용을 붙여넣는 중 %1번째 줄 %2번째 칸에서 오류 발생: %3 + + + + FormWindowSettings + + Form Settings + 폼 설정 + + + Layout &Default + 레이아웃 기본값(&D) + + + &Spacing: + 간격(&S): + + + &Margin: + 여백(&M): + + + &Layout Function + 레이아웃 함수(&L) + + + Ma&rgin: + 여백(&R): + + + Spa&cing: + 간격(&C): + + + &Pixmap Function + 픽스맵 함수(&P) + + + &Include Hints + 힌트 포함(&I) + + + Grid + 격자 + + + Embedded Design + 임베디드 디자인 + + + &Author + 작성자(&A) + + + + IconSelector + + All Pixmaps ( + 모든 픽스맵 ( + + + + ItemPropertyBrowser + + XX Icon Selected off + Sample string to determinate the width for the first column of the list item property browser + XX 아이콘 선택 해제됨 + + + + MainWindowBase + + Main + Not currently used (main tool bar) + + + + File + 파일 + + + Edit + 편집 + + + Tools + 도구 + + + Form + + + + Qt Designer + Qt Designer + + + + NewForm + + Show this Dialog on Startup + 시작할 때 이 대화상자 보이기 + + + C&reate + 생성(&R) + + + Recent + 최근 항목 + + + New Form + 새 폼 + + + &Close + 닫기(&C) + + + &Open... + 열기(&O)... + + + &Recent Forms + 최근 폼(&R) + + + Read error + 읽기 오류 + + + A temporary form file could not be created in %1. + %1에 임시 폼 파일을 만들 수 없습니다. + + + The temporary form file %1 could not be written. + 임시 폼 파일 %1에 쓸 수 없습니다. + + + + ObjectInspectorModel + + Object + 객체 + + + Class + 클래스 + + + separator + 구분자 + + + <noname> + <이름없음> + + + + ObjectNameDialog + + Change Object Name + 객체 이름 바꾸기 + + + Object Name + 객체 이름 + + + + PluginDialog + + Plugin Information + 플러그인 정보 + + + 1 + 1 + + + + PreferencesDialog + + Preferences + 환경 설정 + + + + PreviewConfigurationWidget + + Form + + + + Print/Preview Configuration + 인쇄/미리보기 설정 + + + Style + 스타일 + + + Style sheet + 스타일시트 + + + ... + ... + + + Device skin + 장치 스킨 + + + + PromotionModel + + Not used + Usage of promoted widgets + 사용되지 않음 + + + + Q3WizardContainer + + Page + + + + + QAbstractFormBuilder + + Unexpected element <%1> + 예상하지 못한 원소 <%1> + + + An error has occurred while reading the UI file at line %1, column %2: %3 + UI 파일의 %1번째 줄, %2번째 칸을 읽는 중 오류가 발생하였습니다: %3 + + + Invalid UI file: The root element <ui> is missing. + 잘못된 UI 파일: root 원소 <ui>가 없습니다. + + + The creation of a widget of the class '%1' failed. + 클래스 '%1'을(를) 사용하는 위젯을 만들 수 없습니다. + + + Attempt to add child that is not of class QWizardPage to QWizard. + QWizardPage에서 상속받지 않은 클래스를 QWizard에 추가할 수 없습니다. + + + Attempt to add a layout to a widget '%1' (%2) which already has a layout of non-box type %3. +This indicates an inconsistency in the ui-file. + 상자 형식이 아닌 레이아웃 %3을(를) 가지고 있는 객체 '%1' (%2)에 레이아웃을 추가할 수 없습니다. +UI 파일의 일관성이 깨졌을 수도 있습니다. + + + Empty widget item in %1 '%2'. + %1 '%2'에 빈 위젯 항목이 있습니다. + + + Flags property are not supported yet. + 플래그 속성은 지원하지 않습니다. + + + While applying tab stops: The widget '%1' could not be found. + 탭 멈춤을 적용하는 중: 위젯 '%1'을(를) 찾을 수 없습니다. + + + Invalid QButtonGroup reference '%1' referenced by '%2'. + '%2'에서 잘못된 QButtonGroup 참조 '%1'을(를) 참조하고 있습니다. + + + This version of the uitools library is linked without script support. + 이 버전의 uitools 라이브러리는 스크립트를 지원하지 않습니다. + + + + QAxWidgetPlugin + + ActiveX control + ActiveX 컨트롤 + + + ActiveX control widget + ActiveX 컨트롤 위젯 + + + + QAxWidgetTaskMenu + + Set Control + 컨트롤 설정 + + + Reset Control + 컨트롤 초기화 + + + Licensed Control + 라이선스된 컨트롤 + + + The control requires a design-time license + 이 컨트롤을 사용하려면 라이선스가 필요합니다 + + + + QCoreApplication + + Exception at line %1: %2 + %1번째 줄에서 예외 발생: %2 + + + Unknown error + 알 수 없는 오류 + + + An error occurred while running the script for %1: %2 +Script: %3 + %1의 스크립트를 실행하는 중 오류 발생: %2 +스크립트: %3 + + + %1 is not a promoted class. + %1은(는) 승격된 클래스가 아닙니다. + + + The base class %1 is invalid. + 기본 클래스 %1이(가) 잘못되었습니다. + + + The class %1 already exists. + 클래스 %1이(가) 이미 존재합니다. + + + Promoted Widgets + 승격된 위젯 + + + The class %1 cannot be removed + 클래스 %1을(를) 삭제할 수 없음 + + + The class %1 cannot be removed because it is still referenced. + 클래스 %1이(가) 참조되고 있기 때문에 삭제할 수 없습니다. + + + The class %1 cannot be renamed + 클래스 %1의 이름을 바꿀 수 없음 + + + The class %1 cannot be renamed to an empty name. + 클래스 %1의 이름을 빈 이름으로 바꿀 수 없습니다. + + + There is already a class named %1. + 클래스 %1이(가) 이미 존재합니다. + + + Cannot set an empty include file. + 빈 포함 파일을 설정할 수 없습니다. + + + + QDesigner + + %1 - warning + %1 - 경고 + + + Qt Designer + Qt Designer + + + This application cannot be used for the Console edition of Qt + 이 프로그램은 Qt 콘솔 에디션에서 사용할 수 없습니다 + + + + QDesignerActions + + Saved %1. + %1을(를) 저장하였습니다. + + + %1 already exists. +Do you want to replace it? + %1이(가) 이미 존재합니다. +겹쳐 쓰시겠습니까? + + + Edit Widgets + 위젯 편집 + + + &New... + 새 폼(&N)... + + + &Open... + 열기(&O)... + + + &Save + 저장(&S) + + + Save &As... + 다른 이름으로 저장(&A)... + + + Save A&ll + 모두 저장(&L) + + + Save As &Template... + 템플릿으로 저장(&T)... + + + &Close + 닫기(&C) + + + Save &Image... + 그림 저장(&I)... + + + &Print... + 인쇄(&P)... + + + &Quit + 끝내기(&Q) + + + View &Code... + 코드 보기(&C)... + + + &Minimize + 최소화(&M) + + + Bring All to Front + 모두 앞으로 가져오기 + + + Preferences... + 환경 설정... + + + Additional Fonts... + 추가 글꼴... + + + ALT+CTRL+S + ALT+CTRL+S + + + CTRL+SHIFT+S + CTRL+SHIFT+S + + + CTRL+R + CTRL+R + + + CTRL+M + CTRL+M + + + Qt Designer &Help + Qt Designer 도움말(&H) + + + Current Widget Help + 현재 위젯 도움말 + + + What's New in Qt Designer? + Qt Designer의 새로운 기능 + + + About Plugins + 플러그인 정보 + + + About Qt Designer + Qt Designer 정보 + + + About Qt + Qt 정보 + + + Clear &Menu + 메뉴 비우기(&M) + + + &Recent Forms + 최근 폼(&R) + + + Open Form + 폼 열기 + + + Designer UI files (*.%1);;All Files (*) + Designer UI 파일 (*.%1);;모든 파일 (*) + + + Save Form As + 다른 이름으로 폼 저장 + + + Designer + Designer + + + Feature not implemented yet! + 기능이 구현되지 않았습니다! + + + Code generation failed + 코드 생성 실패 + + + Read error + 읽기 오류 + + + %1 +Do you want to update the file location or generate a new form? + %1 +파일 위치를 업데이트하거나 새 폼을 생성하시겠습니까? + + + &Update + 업데이트(&U) + + + &New Form + 새 폼 생성(&N) + + + Save Form? + 폼을 저장하시겠습니까? + + + Could not open file + 파일을 열 수 없음 + + + The file %1 could not be opened. +Reason: %2 +Would you like to retry or select a different file? + 파일 %1을(를) 열 수 없습니다. +이유: %2 +다시 시도하거나 새 파일을 선택하시겠습니까? + + + Select New File + 새 파일 선택 + + + Could not write file + 파일에 쓸 수 없음 + + + It was not possible to write the entire file %1 to disk. +Reason:%2 +Would you like to retry? + 파일 %1을(를) 디스크에 완전히 기록할 수 없었습니다. +이유: %2 +다시 시도하시겠습니까? + + + Assistant + Assistant + + + &Close Preview + 미리 보기 닫기(&C) + + + The backup file %1 could not be written. + 백업 파일 %1에 쓸 수 없습니다. + + + The backup directory %1 could not be created. + 백업 디렉터리 %1을(를) 만들 수 없습니다. + + + The temporary backup directory %1 could not be created. + 임시 백업 디렉터리 %1을(를) 만들 수 없습니다. + + + Preview failed + 미리 보기 실패 + + + Image files (*.%1) + 그림 파일 (*.%1) + + + Save Image + 그림 저장 + + + Saved image %1. + 그림 %1을(를) 저장하였습니다. + + + The file %1 could not be written. + 파일 %1에 쓸 수 없습니다. + + + Please close all forms to enable the loading of additional fonts. + 추가 글꼴을 불러오려면 모든 폼을 닫아야 합니다. + + + Printed %1. + %1을(를) 인쇄하였습니다. + + + + QDesignerAppearanceOptionsPage + + Appearance + Tab in preferences dialog + 모양 + + + + QDesignerAppearanceOptionsWidget + + Docked Window + 도킹된 창 + + + Multiple Top-Level Windows + 여러 최상위 창 + + + Toolwindow Font + 도구 창 글꼴 + + + + QDesignerAxWidget + + Reset control + 컨트롤 초기화 + + + Set control + 컨트롤 설정 + + + Control loaded + 컨트롤 불러옴 + + + A COM exception occurred when executing a meta call of type %1, index %2 of "%3". + "%3"의 메타 호출(형식 %1, 인덱스 %2)을 실행하는 중 COM 오류가 발생하였습니다. + + + + QDesignerFormBuilder + + Script errors occurred: + 발생한 스크립트 오류: + + + The preview failed to build. + 미리 보기를 빌드할 수 없습니다. + + + Designer + Designer + + + + QDesignerFormWindow + + %1 - %2[*] + %1 - %2[*] + + + Save Form? + 폼을 저장하시겠습니까? + + + Do you want to save the changes to this document before closing? + 닫기 전에 이 문서의 변경 사항을 저장하시겠습니까? + + + If you don't save, your changes will be lost. + 저장하지 않은 변경 사항은 손실될 것입니다. + + + + QDesignerMenu + + Type Here + 여기에 입력하십시오 + + + Add Separator + 구분자 추가 + + + Insert separator + 구분자 삽입 + + + Remove separator + 구분자 삭제 + + + Remove action '%1' + 동작 '%1' 삭제 + + + Add separator + 구분자 추가 + + + Insert action + 동작 삽입 + + + + QDesignerMenuBar + + Type Here + 여기에 입력하십시오 + + + Remove Menu '%1' + '%1' 메뉴 삭제 + + + Remove Menu Bar + 메뉴 표시줄 삭제 + + + Menu + 메뉴 + + + + QDesignerPluginManager + + An XML error was encountered when parsing the XML of the custom widget %1: %2 + 사용자 정의 위젯 %1의 XML을 처리하는 중 XML 오류가 발생하였습니다: %2 + + + A required attribute ('%1') is missing. + 필요한 속성 '%1'이(가) 없습니다. + + + An invalid property specification ('%1') was encountered. Supported types: %2 + 잘못된 속성 정의 '%1이(가) 존재합니다. 지원하는 형식: %2 + + + '%1' is not a valid string property specification. + '%1'은(는) 올바른 문자열 속성 정의가 아닙니다. + + + The XML of the custom widget %1 does not contain any of the elements <widget> or <ui>. + 사용자 정의 위젯 %1의 XML 파일에 <widget>이나 <ui> 원소가 존재하지 않습니다. + + + The class attribute for the class %1 is missing. + 클래스 %1의 class 속성이 없습니다. + + + The class attribute for the class %1 does not match the class name %2. + 클래스 %1의 class 속성이 클래스 이름 %2와(과) 일치하지 않습니다. + + + + QDesignerPropertySheet + + Dynamic Properties + 동적 속성 + + + + QDesignerResource + + The layout type '%1' is not supported, defaulting to grid. + 레이아웃 형식 '%1'은(는) 지원하지 않습니다. 기본값으로 격자 레이아웃을 사용합니다. + + + The container extension of the widget '%1' (%2) returned a widget not managed by Designer '%3' (%4) when queried for page #%5. +Container pages should only be added by specifying them in XML returned by the domXml() method of the custom widget. + 위젯 '%1' (%2)의 컨테이너 확장에 쪽 #%5을(를) 조회하였을 때 Designer에서 관리되지 않는 위젯 '%3'(%4)을(를) 반환하였습니다. +컨테이너 쪽은 사용자 정의 위젯의 domXml() 메서드에서 반환하는 XML에 정의하여야 합니다. + + + Unexpected element <%1> + Parsing clipboard contents + 예상하지 못한 원소 <%1> + + + Error while pasting clipboard contents at line %1, column %2: %3 + Parsing clipboard contents + 클립보드 내용을 붙여넣는 중 %1번째 줄 %2번째 칸에서 오류 발생: %3 + + + Error while pasting clipboard contents: The root element <ui> is missing. + Parsing clipboard contents + 클립보드 내용을 붙여넣는 중 오류 발생: 루트 원소 <ui>가 없습니다. + + + + QDesignerSharedSettings + + The template path %1 could not be created. + 템플릿 경로 %1을(를) 생성할 수 없습니다. + + + An error has been encountered while parsing device profile XML: %1 + 장치 프로필 XML을 처리하는 중 오류 발생: %1 + + + + QDesignerToolWindow + + Property Editor + 속성 편집기 + + + Action Editor + 동작 편집기 + + + Object Inspector + 객체 탐색기 + + + Resource Browser + 리소스 탐색기 + + + Signal/Slot Editor + 시그널/슬롯 편집기 + + + Widget Box + 위젯 상자 + + + + QDesignerWorkbench + + &File + 파일(&F) + + + Edit + 편집 + + + F&orm + 폼(&O) + + + Preview in + 다음으로 미리 보기 + + + &View + 보기(&V) + + + &Settings + 설정(&S) + + + &Window + 창(&W) + + + &Help + 도움말(&H) + + + Toolbars + 도구 모음 + + + Widget Box + 위젯 상자 + + + Save Forms? + 폼을 저장하시겠습니까? + + + There are %n forms with unsaved changes. Do you want to review these changes before quitting? + + 저장하지 않은 변경 사항이 있는 폼이 %n개 있습니다. 끝내기 전에 변경 사항을 검토하시겠습니까? + + + + If you do not review your documents, all your changes will be lost. + 변경 사항을 검토하지 않으면 손실될 것입니다. + + + Discard Changes + 변경 사항 무시 + + + Review Changes + 변경 사항 검토 + + + Backup Information + 백업 정보 + + + The last session of Designer was not terminated correctly. Backup files were left behind. Do you want to load them? + Designer가 마지막으로 실행되었을 때 올바르게 종료되지 않았으며, 백업 파일이 생성되었습니다. 백업 파일을 불러오시겠습니까? + + + The file <b>%1</b> could not be opened. + 파일 <b>%1</b>을(를) 열 수 없습니다. + + + The file <b>%1</b> is not a valid Designer UI file. + 파일 <b>%1</b>은(는) 올바른 Designer UI 파일이 아닙니다. + + + + QFormBuilder + + An empty class name was passed on to %1 (object name: '%2'). + Empty class name passed to widget factory method +---------- +Empty class name passed to widget factory method +---------- +Empty class name passed to widget factory method + %1(객체 이름: '%2')에 빈 클래스 이름이 전달되었습니다. + + + QFormBuilder was unable to create a custom widget of the class '%1'; defaulting to base class '%2'. + QFormBuilder에서 클래스 '%1'인 사용자 정의 위젯을 만들 수 없습니다. 기본 클래스 '%2'을(를) 사용합니다. + + + QFormBuilder was unable to create a widget of the class '%1'. + QFormBuilder에서 클래스 '%1'인 위젯을 만들 수 없습니다. + + + The layout type `%1' is not supported. + 레이아웃 형식 '%1'은(는) 지원하지 않습니다. + + + The set-type property %1 could not be read. + set 형식 속성 %1을(를) 읽을 수 없습니다. + + + The enumeration-type property %1 could not be read. + 열거형 속성 %1을(를) 읽을 수 없습니다. + + + Reading properties of the type %1 is not supported yet. + 형식이 %1인 속성에서 읽기는 지원하지 않습니다. + + + The property %1 could not be written. The type %2 is not supported yet. + 속성 %1에 쓸 수 없습니다. 형식 %2은(는) 지원하지 않습니다. + + + The enumeration-value '%1' is invalid. The default value '%2' will be used instead. + 열거형 값 '%1'이(가) 잘못되었습니다. 기본값 '%2'을(를) 사용합니다. + + + The flag-value '%1' is invalid. Zero will be used instead. + 플래그 값 '%1'이(가) 잘못되었습니다. 0을 사용합니다. + + + + QStackedWidgetEventFilter + + Previous Page + 이전 쪽 + + + Next Page + 다음 쪽 + + + Delete + 삭제 + + + Before Current Page + 현재 쪽 앞에 + + + After Current Page + 현재 쪽 뒤에 + + + Change Page Order... + 쪽 순서 변경... + + + Change Page Order + 쪽 순서 변경 + + + Page %1 of %2 + %2 중 %1쪽 + + + Insert Page + 쪽 삽입 + + + + QStackedWidgetPreviewEventFilter + + Go to previous page of %1 '%2' (%3/%4). + %1 '%2'의 이전 쪽으로 이동합니다 (%3/%4). + + + Go to next page of %1 '%2' (%3/%4). + %1 '%2'의 다음 쪽으로 이동합니다 (%3/%4). + + + + QTabWidgetEventFilter + + Delete + 삭제 + + + Before Current Page + 현재 쪽 앞에 + + + After Current Page + 현재 쪽 다음에 + + + Page %1 of %2 + %2 중 %1쪽 + + + Insert Page + 쪽 삽입 + + + + QToolBoxHelper + + Delete Page + 쪽 삭제 + + + Before Current Page + 현재 쪽 앞에 + + + After Current Page + 현재 쪽 뒤에 + + + Change Page Order... + 쪽 순서 변경... + + + Change Page Order + 쪽 순서 변경 + + + Page %1 of %2 + %2 중 %1쪽 + + + Insert Page + 쪽 삽입 + + + + QtBoolEdit + + True + + + + False + 거짓 + + + + QtBoolPropertyManager + + True + + + + False + 거짓 + + + + QtCharEdit + + Clear Char + 문자 삭제 + + + + QtColorEditWidget + + ... + ... + + + + QtColorPropertyManager + + Red + 빨강 + + + Green + 녹색 + + + Blue + 파랑 + + + Alpha + 투명도 + + + + QtCursorDatabase + + Arrow + 화살표 + + + Up Arrow + 위쪽 화살표 + + + Cross + 십자가 + + + Wait + 대기 + + + IBeam + I빔 + + + Size Vertical + 수직 크기 조정 + + + Size Horizontal + 수평 크기 조정 + + + Size Backslash + 역슬래시 크기 조정 + + + Size Slash + 슬래시 크기 조정 + + + Size All + 모든 방향 크기 조정 + + + Blank + 비어 있음 + + + Split Vertical + 수직 나누기 + + + Split Horizontal + 수평 나누기 + + + Pointing Hand + 가리키는 손 + + + Forbidden + 금지됨 + + + Open Hand + 열린 손 + + + Closed Hand + 닫힌 손 + + + What's This + 도움말 항목 + + + Busy + 바쁨 + + + + QtFontEditWidget + + ... + ... + + + Select Font + 글꼴 선택 + + + + QtFontPropertyManager + + Family + 종류 + + + Point Size + 포인트 크기 + + + Bold + 굵게 + + + Italic + 기울임꼴 + + + Underline + 밑줄 + + + Strikeout + 취소선 + + + Kerning + 커닝 + + + + QtGradientDialog + + Edit Gradient + 그라데이션 편집 + + + + QtGradientEditor + + Form + + + + Gradient Editor + 그라데이션 편집기 + + + This area shows a preview of the gradient being edited. It also allows you to edit parameters specific to the gradient's type such as start and final point, radius, etc. by drag & drop. + 현재 편집하고 있는 그라데이션을 미리 보여 줍니다. 그라데이션의 시작과 끝점, 반지름 등을 끌어다 놓기로 편집할 수 있습니다. + + + 1 + 1 + + + 2 + 2 + + + 3 + 3 + + + 4 + 4 + + + 5 + 5 + + + Gradient Stops Editor + 그라데이션 지점 편집기 + + + This area allows you to edit gradient stops. Double click on the existing stop handle to duplicate it. Double click outside of the existing stop handles to create a new stop. Drag & drop the handle to reposition it. Use right mouse button to popup context menu with extra actions. + 그라데이션 지점을 편집할 수 있습니다. 존재하는 지점을 두 번 누르면 복제됩니다. 존재하는 지점 밖을 두 번 누르면 새 지점을 만들 수 있습니다. 지점의 위치를 바꾸려면 끌어다 놓으십시오. 마우스 오른쪽 단추를 누르면 추가 동작이 있는 팝업 메뉴가 표시됩니다. + + + Zoom + 확대/축소 + + + Reset Zoom + 원래 크기로 + + + Position + 위치 + + + Hue + 명도 + + + H + H + + + Saturation + 채도 + + + S + S + + + Sat + 채도 + + + Value + 휘도 + + + V + V + + + Val + 휘도 + + + Alpha + 투명도 + + + A + A + + + Type + 종류 + + + Spread + 펼침 + + + Color + 색상 + + + Current stop's color + 현재 지점의 색상 + + + Show HSV specification + HSV로 색상 표시 + + + HSV + HSV + + + Show RGB specification + RGB로 색상 표시 + + + RGB + RGB + + + Current stop's position + 현재 지점의 위치 + + + % + % + + + Zoom In + 확대 + + + Zoom Out + 축소 + + + Toggle details extension + 자세한 정보 보이기/숨기기 + + + > + > + + + Linear Type + 선형 + + + ... + ... + + + Radial Type + 원형 + + + Conical Type + 원뿔형 + + + Pad Spread + 패딩 + + + Repeat Spread + 반복 + + + Reflect Spread + 반사 + + + Start X + 시작 X + + + Start Y + 시작 Y + + + Final X + 끝 X + + + Final Y + 끝 Y + + + Central X + 중간 X + + + Central Y + 중간 Y + + + Focal X + 초점 X + + + Focal Y + 초점 Y + + + Radius + 반지름 + + + Angle + 각도 + + + Linear + 선형 + + + Radial + 원형 + + + Conical + 원뿔형 + + + Pad + 패딩 + + + Repeat + 반복 + + + Reflect + 반사 + + + + QtGradientStopsWidget + + New Stop + 새 지점 + + + Delete + 삭제 + + + Flip All + 모두 뒤집기 + + + Select All + 모두 선택 + + + Zoom In + 확대 + + + Zoom Out + 축소 + + + Reset Zoom + 원래 크기로 + + + + QtGradientView + + Gradient View + 그라데이션 보기 + + + New... + 새로 만들기... + + + Edit... + 편집... + + + Rename + 이름 바꾸기 + + + Remove + 삭제 + + + Grad + 그라데이션 + + + Remove Gradient + 그라데이션 삭제 + + + Are you sure you want to remove the selected gradient? + 선택한 그라데이션을 삭제하시겠습니까? + + + + QtGradientViewDialog + + Select Gradient + 그라데이션 선택 + + + + QtKeySequenceEdit + + Clear Shortcut + 단축키 삭제 + + + + QtLocalePropertyManager + + <Invalid> + <잘못됨> + + + %1, %2 + %1, %2 + + + Language + 언어 + + + Country + 국가 + + + + QtPointFPropertyManager + + (%1, %2) + (%1, %2) + + + X + X + + + Y + Y + + + + QtPointPropertyManager + + (%1, %2) + (%1, %2) + + + X + X + + + Y + Y + + + + QtPropertyBrowserUtils + + [%1, %2, %3] (%4) + [%1, %2, %3] (%4) + + + [%1, %2] + [%1, %2] + + + + QtRectFPropertyManager + + [(%1, %2), %3 x %4] + [(%1, %2), %3 x %4] + + + X + X + + + Y + Y + + + Width + 너비 + + + Height + 높이 + + + + QtRectPropertyManager + + [(%1, %2), %3 x %4] + [(%1, %2), %3 x %4] + + + X + X + + + Y + Y + + + Width + 너비 + + + Height + 높이 + + + + QtResourceEditorDialog + + Dialog + 대화 상자 + + + New File + 새 파일 + + + N + N + + + Remove File + 파일 삭제 + + + R + R + + + I + I + + + New Resource + 새 리소스 + + + A + A + + + Remove Resource or File + 리소스나 파일 삭제 + + + %1 already exists. +Do you want to replace it? + %1이(가) 이미 존재합니다. +변경하시겠습니까? + + + The file does not appear to be a resource file; element '%1' was found where '%2' was expected. + 이 파일은 리소스 파일이 아닌 것 같습니다. 원소 '%2'을(를) 예상하였지만 '%1'이(가) 나왔습니다. + + + %1 [read-only] + %1 [읽기 전용] + + + %1 [missing] + %1 [없음] + + + <no prefix> + <접두사 없음> + + + New Resource File + 새 리소스 파일 + + + Resource files (*.qrc) + 리소스 파일 (*.qrc) + + + Import Resource File + 리소스 파일 가져오기 + + + newPrefix + newPrefix + + + <p><b>Warning:</b> The file</p><p>%1</p><p>is outside of the current resource file's parent directory.</p> + <p><b>경고:</b> 파일</p><p>%1</p><p>이(가) 현재 리소스 파일의 부모 디렉터리 밖에 있습니다.</p> + + + <p>To resolve the issue, press:</p><table><tr><th align="left">Copy</th><td>to copy the file to the resource file's parent directory.</td></tr><tr><th align="left">Copy As...</th><td>to copy the file into a subdirectory of the resource file's parent directory.</td></tr><tr><th align="left">Keep</th><td>to use its current location.</td></tr></table> + <p>이 문제를 해결하려면 다음 중에서 선택하십시오:</p><table><tr><th align="left">복사</th><td>리소스 파일의 부모 디렉터리로 파일을 복사합니다.</td></tr><tr><th align="left">다른 이름으로 복사...</th><tr>리소스 파일의 부모 디렉터리의 하위 디렉터리로 파일을 복사합니다.</td></tr><tr><th align="left">유지</th><td>현재 위치를 유지합니다.</td></tr></table> + + + Add Files + 파일 추가 + + + Incorrect Path + 경로 잘못됨 + + + Copy + 복사 + + + Copy As... + 다른 이름으로 복사... + + + Keep + 유지 + + + Skip + 건너뛰기 + + + Clone Prefix + 접두사 복제 + + + Enter the suffix which you want to add to the names of the cloned files. +This could for example be a language extension like "_de". + 복제된 파일의 끝에 추가할 접미사를 입력하십시오. +예를 들어 언어 코드 "_ko" 등을 사용할 수 있습니다. + + + Copy As + 다른 이름으로 복사 + + + <p>The selected file:</p><p>%1</p><p>is outside of the current resource file's directory:</p><p>%2</p><p>Please select another path within this directory.<p> + <p>선택한 파일</p><p>%1</p>이(가) 현재 리소스 파일의 디렉터리</p><p>%2</p><p>밖에 있습니다. 이 디렉터리 안에 있는 다른 경로를 선택하십시오.</p> + + + Could not overwrite %1. + %1에 겹쳐쓸 수 없습니다. + + + Could not copy +%1 +to +%2 + %1 +을(를) +%2 +(으)로 복사할 수 없습니다 + + + A parse error occurred at line %1, column %2 of %3: +%4 + %3의 %1번째 줄, %2번째 칸에서 처리 오류가 발생하였습니다: +%4 + + + Save Resource File + 리소스 파일 저장 + + + Could not write %1: %2 + %1에 쓸 수 없음: %2 + + + Edit Resources + 리소스 편집 + + + New... + 새로 만들기... + + + Open... + 열기... + + + Open Resource File + 리소스 파일 열기 + + + Remove + 삭제 + + + Move Up + 위로 이동 + + + Move Down + 아래로 이동 + + + Add Prefix + 접두사 추가 + + + Add Files... + 파일 추가... + + + Change Prefix + 접두사 변경 + + + Change Language + 언어 변경 + + + Change Alias + 별명 변경 + + + Clone Prefix... + 접두사 복제... + + + Prefix / Path + 접두사 / 경로 + + + Language / Alias + 언어 / 별명 + + + <html><p><b>Warning:</b> There have been problems while reloading the resources:</p><pre>%1</pre></html> + <html><p><b>경고:</b> 다음 리소스을 다시 불러오는 중 오류가 발생하였습니다:</p><pre>%1</pre></html> + + + Resource Warning + 리소스 경고 + + + + QtResourceView + + Size: %1 x %2 +%3 + 크기: %1 x %2 +%3 + + + Edit Resources... + 리소스 편집... + + + Reload + 새로 고침 + + + Copy Path + 경로 복사 + + + + QtResourceViewDialog + + Select Resource + 리소스 선택 + + + + QtSizeFPropertyManager + + %1 x %2 + %1 x %2 + + + Width + 너비 + + + Height + 높이 + + + + QtSizePolicyPropertyManager + + <Invalid> + <잘못됨> + + + [%1, %2, %3, %4] + [%1, %2, %3, %4] + + + Horizontal Policy + 수평 정책 + + + Vertical Policy + 수직 정책 + + + Horizontal Stretch + 수평 확장 + + + Vertical Stretch + 수직 확장 + + + + QtSizePropertyManager + + %1 x %2 + %1 x %2 + + + Width + 너비 + + + Height + 높이 + + + + QtToolBarDialog + + Customize Toolbars + 도구 모음 사용자 정의 + + + 1 + 1 + + + Actions + 동작 + + + Toolbars + 도구 모음 + + + Add new toolbar + 새 도구 모음 추가 + + + New + 새로 만들기 + + + Remove selected toolbar + 선택한 도구 모음 삭제 + + + Remove + 삭제 + + + Rename toolbar + 도구 모음 이름 바꾸기 + + + Rename + 이름 바꾸기 + + + Move action up + 동작 위로 이동 + + + Up + 위로 + + + Remove action from toolbar + 도구 모음에서 동작 삭제 + + + <- + <- + + + Add action to toolbar + 도구 모음에 동작 추가 + + + -> + -> + + + Move action down + 동작 아래로 이동 + + + Down + 아래로 + + + Current Toolbar Actions + 현재 도구 모음의 동작 + + + Custom Toolbar + 사용자 정의 도구 모음 + + + < S E P A R A T O R > + < 구 분 자 > + + + + QtTreePropertyBrowser + + Property + 속성 + + + Value + + + + + SaveFormAsTemplate + + Save Form As Template + 폼을 템플릿으로 저장 + + + &Name: + 이름(&N): + + + &Category: + 분류(&C): + + + Add path... + 경로 추가... + + + Template Exists + 템플릿이 존재함 + + + A template with the name %1 already exists. +Do you want overwrite the template? + 이름이 %1인 템플릿이 이미 존재합니다. +템플릿을 겹쳐 쓰시겠습니까? + + + Overwrite Template + 템플릿 겹쳐 쓰기 + + + Open Error + 열기 오류 + + + There was an error opening template %1 for writing. Reason: %2 + 템플릿 %1에 쓰기 위해 열 수 없습니다. 이유: %2 + + + Write Error + 쓰기 오류 + + + There was an error writing the template %1 to disk. Reason: %2 + 템플릿 %1을(를) 디스크에 쓰는 중 오류가 발생하였습니다. 이유: %2 + + + Pick a directory to save templates in + 템플릿 저장 디렉터리 선택 + + + + ScriptErrorDialog + + An error occurred while running the scripts for "%1": + + "%1"의 스크립트를 실행하는 중 오류 발생: + + + + + SelectSignalDialog + + Go to slot + 슬롯으로 이동 + + + Select signal + 시그널 선택 + + + signal + 시그널 + + + class + 클래스 + + + + SignalSlotConnection + + SENDER(%1), SIGNAL(%2), RECEIVER(%3), SLOT(%4) + SENDER(%1), SIGNAL(%2), RECEIVER(%3), SLOT(%4) + + + + SignalSlotDialogClass + + Signals and slots + 시그널과 슬롯 + + + Slots + 슬롯 + + + Add + 추가 + + + ... + ... + + + Delete + 삭제 + + + Signals + 시그널 + + + + Spacer + + Horizontal Spacer '%1', %2 x %3 + 수평 스페이서 '%1', %2 x %3 + + + Vertical Spacer '%1', %2 x %3 + 수직 스페이서 '%1', %2 x %3 + + + + TemplateOptionsPage + + Template Paths + Tab in preferences dialog + 템플릿 경로 + + + + ToolBarManager + + Configure Toolbars... + 도구 모음 설정... + + + Window + + + + Help + 도움말 + + + Style + 스타일 + + + Dock views + 보기 도킹 + + + File + 파일 + + + Edit + 편집 + + + Tools + 도구 + + + Form + + + + Toolbars + 도구 모음 + + + + VersionDialog + + <h3>%1</h3><br/><br/>Version %2 + <h3>%1</h3><br/><br/>버전 %2 + + + Qt Designer + Qt Designer + + + <br/>Qt Designer is a graphical user interface designer for Qt applications.<br/> + <br/>Qt Designer는 Qt 프로그램의 그래픽 사용자 인터페이스 디자이너입니다.<br/> + + + %1<br/>Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + %1<br/>저작권자 (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + + + + VideoPlayerTaskMenu + + Available Mime Types + 사용 가능한 MIME 형식 + + + Display supported mime types... + 지원하는 MIME 형식 표시... + + + Load... + 불러오기... + + + Play + 재생 + + + Pause + 일시 정지 + + + Stop + 정지 + + + Choose Video Player Media Source + 비디오 재생기 미디어 원본 선택 + + + An error has occurred in '%1': %2 + '%1'에서 오류 발생: %2 + + + Video Player Error + 비디오 재생기 오류 + + + + WidgetDataBase + + The file contains a custom widget '%1' whose base class (%2) differs from the current entry in the widget database (%3). The widget database is left unchanged. + 이 파일에는 사용자 정의 위젯 '%1'이(가) 포함되어 있으며, 정의된 기본 클래스(%2)가 위젯 데이터베이스의 항목(%3)에 정의된 것과 다릅니다. 위젯 데이터베이스는 변경되지 않았습니다. + + + + qdesigner_internal::ActionEditor + + New... + 새로 만들기... + + + Edit... + 편집... + + + Go to slot... + 슬롯으로 이동... + + + Copy + 복사 + + + Cut + 잘라내기 + + + Paste + 붙여넣기 + + + Select all + 모두 선택 + + + Delete + 삭제 + + + Actions + 동작 + + + Configure Action Editor + 동작 편집기 설정 + + + Icon View + 아이콘 보기 + + + Detailed View + 자세히 보기 + + + New action + 새 동작 + + + Edit action + 동작 편집 + + + Remove action '%1' + 동작 '%1' 삭제 + + + Remove actions + 동작 삭제 + + + Used In + 다음에 사용됨 + + + + qdesigner_internal::ActionModel + + Name + 이름 + + + Used + 사용됨 + + + Text + 텍스트 + + + Shortcut + 단축키 + + + Checkable + 선택 가능 + + + ToolTip + 풍선 도움말 + + + + qdesigner_internal::BrushManagerProxy + + The element '%1' is missing the required attribute '%2'. + 원소 '%1'에 필요한 속성 '%2'이(가) 없습니다. + + + Empty brush name encountered. + 브러시 이름이 비어 있습니다. + + + An unexpected element '%1' was encountered. + 예상하지 못한 원소 '%1'이(가) 있습니다. + + + An error occurred when reading the brush definition file '%1' at line line %2, column %3: %4 + 브러시 정의 파일 '%1'의 %2번째 줄, %3번째 칸을 읽는 중 오류 발생: %4 + + + An error occurred when reading the resource file '%1' at line %2, column %3: %4 + 리소스 파일 '%1'의 %2번째 줄, %3번째 칸을 읽는 중 오류 발생: %4 + + + + qdesigner_internal::BuddyEditor + + Add buddy + 친구 추가 + + + Remove buddies + 친구 삭제 + + + Remove %n buddies + + 친구 %n개 삭제 + + + + Add %n buddies + + 친구 %n개 추가 + + + + Set automatically + 자동으로 설정 + + + + qdesigner_internal::BuddyEditorPlugin + + Edit Buddies + 친구 편집 + + + + qdesigner_internal::BuddyEditorTool + + Edit Buddies + 친구 편집 + + + + qdesigner_internal::ButtonGroupMenu + + Select members + 구성원 선택 + + + Break + 풀기 + + + + qdesigner_internal::ButtonTaskMenu + + Assign to button group + 단추 그룹에 할당 + + + Button group + 단추 그룹 + + + New button group + 새 단추 그룹 + + + Change text... + 텍스트 바꾸기... + + + None + 없음 + + + Button group '%1' + 단추 그룹 '%1' + + + + qdesigner_internal::CodeDialog + + Save... + 저장... + + + Copy All + 모두 복사 + + + &Find in Text... + 텍스트에서 찾기(&F)... + + + A temporary form file could not be created in %1. + %1에 임시 폼 파일을 만들 수 없습니다. + + + The temporary form file %1 could not be written. + 임시 폼 파일 %1에 쓸 수 없습니다. + + + %1 - [Code] + %1 - [코드] + + + Save Code + 코드 저장 + + + Header Files (*.%1) + 헤더 파일 (*.%1) + + + The file %1 could not be opened: %2 + 파일 %1을(를) 열 수 없습니다: %2 + + + The file %1 could not be written: %2 + 파일 %1에 쓸 수 없습니다: %2 + + + %1 - Error + %1 - 오류 + + + + qdesigner_internal::ColorAction + + Text Color + 글자 색 + + + + qdesigner_internal::ComboBoxTaskMenu + + Edit Items... + 항목 편집... + + + Change Combobox Contents + 콤보 상자 내용 변경 + + + + qdesigner_internal::CommandLinkButtonTaskMenu + + Change description... + 설명 변경... + + + + qdesigner_internal::ConnectionEdit + + Select All + 모두 선택 + + + Deselect All + 모두 선택 해제 + + + Delete + 삭제 + + + + qdesigner_internal::ConnectionModel + + Sender + 송신자 + + + Signal + 시그널 + + + Receiver + 수신자 + + + Slot + 슬롯 + + + <sender> + <송신자> + + + <signal> + <시그널> + + + <receiver> + <수신자> + + + <slot> + <슬롯> + + + The connection already exists!<br>%1 + 이미 연결되어 있습니다!<br>%1 + + + Signal and Slot Editor + 시그널/슬롯 편집기 + + + + qdesigner_internal::ContainerWidgetTaskMenu + + Delete + 삭제 + + + Insert + 삽입 + + + Insert Page Before Current Page + 현재 쪽 앞에 쪽 삽입 + + + Insert Page After Current Page + 현재 쪽 다음에 쪽 삽입 + + + Add Subwindow + 하위 창 추가 + + + Subwindow + 하위 창 + + + Page + + + + Page %1 of %2 + %2 중 %1쪽 + + + + qdesigner_internal::DPI_Chooser + + System (%1 x %2) + System resolution + 시스템 (%1 x %2) + + + User defined + 사용자 정의 + + + x + DPI X/Y separator + x + + + + qdesigner_internal::DesignerPropertyManager + + AlignLeft + 왼쪽정렬 + + + AlignHCenter + 수평가운데정렬 + + + AlignRight + 오른쪽정렬 + + + AlignJustify + 양쪽맞춤 + + + AlignTop + 위로정렬 + + + AlignVCenter + 수직가운데정렬 + + + AlignBottom + 아래로정렬 + + + %1, %2 + %1, %2 + + + Customized (%n roles) + + 사용자 정의 (역할 %n개) + + + + Inherited + 상속됨 + + + Horizontal + 수평 + + + Vertical + 수직 + + + Normal Off + 일반 꺼짐 + + + Normal On + 일반 켜짐 + + + Disabled Off + 사용 불가능 꺼짐 + + + Disabled On + 사용 불가능 켜짐 + + + Active Off + 활성 꺼짐 + + + Active On + 활성 켜짐 + + + Selected Off + 선택 꺼짐 + + + Selected On + 선택 켜짐 + + + translatable + 번역가능 + + + disambiguation + 동음이의 + + + comment + 설명 + + + + qdesigner_internal::DeviceProfileDialog + + Device Profiles (*.%1) + 장치 프로필 (*.%1) + + + Default + 기본값 + + + Save Profile + 프로필 저장 + + + Save Profile - Error + 프로필 저장 - 오류 + + + Unable to open the file '%1' for writing: %2 + 파일 %1에 쓰기 위해 열 수 없습니다: %2 + + + Open profile + 프로필 열기 + + + Open Profile - Error + 프로필 열기 - 오류 + + + Unable to open the file '%1' for reading: %2 + 파일 %1에서 읽기 위해 열 수 없습니다: %2 + + + '%1' is not a valid profile: %2 + '%1'은(는) 올바른 프로필이 아닙니다: %2 + + + + qdesigner_internal::Dialog + + Dialog + 대화 상자 + + + StringList + 문자열 목록 + + + New String + 새 문자열 + + + &New + 새로 만들기(&N) + + + Delete String + 문자열 삭제 + + + &Delete + 삭제(&D) + + + &Value: + 값(&V): + + + Move String Up + 문자열 위로 이동 + + + Up + 위로 + + + Move String Down + 문자열 아래로 이동 + + + Down + 아래로 + + + + qdesigner_internal::EmbeddedOptionsControl + + None + 없음 + + + Add a profile + 프로필 추가 + + + Edit the selected profile + 선택한 프로필 편집 + + + Delete the selected profile + 선택한 프로필 삭제 + + + Add Profile + 프로필 추가 + + + New profile + 새 프로필 + + + Edit Profile + 프로필 편집 + + + Delete Profile + 프로필 삭제 + + + Would you like to delete the profile '%1'? + 프로필 '%1'을(를) 삭제하시겠습니까? + + + Default + 기본값 + + + + qdesigner_internal::FilterWidget + + Filter + 필터 + + + Clear text + 텍스트 삭제 + + + + qdesigner_internal::FormEditor + + Resource File Changed + 리소스 파일 변경됨 + + + The file "%1" has changed outside Designer. Do you want to reload it? + 파일 "%1"이(가) Designer 밖에서 편집되었습니다. 다시 불러오시겠습니까? + + + + qdesigner_internal::FormLayoutMenu + + Add form layout row... + 폼 레이아웃 행 추가... + + + + qdesigner_internal::FormWindow + + Edit contents + 내용 편집 + + + F2 + F2 + + + Insert widget '%1' + 위젯 '%1' 삽입 + + + Resize + 크기 조정 + + + Key Resize + 키 크기 조정 + + + Key Move + 키 이동 + + + Paste %n action(s) + + 동작 %n개 붙여넣기 + + + + Paste %n widget(s) + + 위젯 %n개 붙여넣기 + + + + Paste (%1 widgets, %2 actions) + 붙여넣기 (위젯 %1개, 동작 %2개) + + + Cannot paste widgets. Designer could not find a container without a layout to paste into. + 위젯을 붙여넣을 수 없습니다. Designer에서 레이아웃이 없는 위젯을 붙여넣을 컨테이너를 찾을 수 없습니다. + + + Break the layout of the container you want to paste into, select this container and then paste again. + 붙여넣을 컨테이너의 레이아웃을 푼 다음, 이 컨테이너를 다시 선택하고 붙여넣으십시오. + + + Paste error + 붙여넣기 오류 + + + Raise widgets + 위젯 올리기 + + + Lower widgets + 위젯 내리기 + + + Select Ancestor + 조상 선택 + + + Lay out + 배치 + + + Drop widget + 위젯 추가하기 + + + A QMainWindow-based form does not contain a central widget. + QMainWindow 기반 폼은 중심 위젯을 포함하지 않습니다. + + + + qdesigner_internal::FormWindowBase + + Delete '%1' + '%1' 삭제 + + + Delete + 삭제 + + + + qdesigner_internal::FormWindowManager + + Cu&t + 잘라내기(&T) + + + Cuts the selected widgets and puts them on the clipboard + 선택한 위젯을 잘라내고 클립보드에 붙여 넣습니다 + + + &Copy + 복사(&C) + + + Copies the selected widgets to the clipboard + 선택한 위젯을 클립보드로 복사합니다 + + + &Paste + 붙여넣기(&P) + + + Pastes the clipboard's contents + 클립보드의 내용을 붙여 넣습니다 + + + &Delete + 삭제(&D) + + + Deletes the selected widgets + 선택한 위젯을 삭제합니다 + + + Select &All + 모두 선택(&A) + + + Selects all widgets + 모든 위젯을 선택합니다 + + + Bring to &Front + 앞으로 가져오기(&F) + + + Raises the selected widgets + 선택한 위젯을 앞으로 가져옵니다 + + + Send to &Back + 뒤로 보내기(&B) + + + Lowers the selected widgets + 선택한 위젯을 뒤로 보냅니다 + + + Adjust &Size + 크기 조정(&S) + + + Adjusts the size of the selected widget + 선택한 위젯의 크기를 조정합니다 + + + Lay Out &Horizontally + 수평으로 배치(&H) + + + Lays out the selected widgets horizontally + 선택한 위젯을 수평으로 배치합니다 + + + Lay Out &Vertically + 수직으로 배치(&V) + + + Lays out the selected widgets vertically + 선택한 위젯을 수직으로 배치합니다 + + + Lay Out in a &Form Layout + 폼 레이아웃으로 배치(&F) + + + Lays out the selected widgets in a form layout + 선택한 위젯을 폼 레이아웃으로 배치합니다 + + + Lay Out in a &Grid + 격자형으로 배치(&G) + + + Lays out the selected widgets in a grid + 선택한 위젯을 격자형으로 배치합니다 + + + Lay Out Horizontally in S&plitter + 구분자를 사용하여 수평으로 배치(&P) + + + Lays out the selected widgets horizontally in a splitter + 선택한 위젯을 구분자를 사용하여 수평으로 배치합니다 + + + Lay Out Vertically in Sp&litter + 구분자를 사용하여 수직으로 배치(&L) + + + Lays out the selected widgets vertically in a splitter + 선택한 위젯을 구분자를 사용하여 수직으로 배치합니다 + + + &Break Layout + 레이아웃 풀기(&B) + + + Breaks the selected layout + 선택한 레이아웃을 풉니다 + + + Si&mplify Grid Layout + 격자 레이아웃 간단하게 하기(&M) + + + Removes empty columns and rows + 비어 있는 행과 열을 삭제합니다 + + + &Preview... + 미리 보기(&P)... + + + Preview current form + 현재 폼을 미리 봅니다 + + + Form &Settings... + 폼 설정(&S)... + + + Break Layout + 레이아웃 풀기 + + + Adjust Size + 크기 조정 + + + Could not create form preview + Title of warning message box + 폼을 미리볼 수 없음 + + + Form Settings - %1 + 폼 설정 - %1 + + + + qdesigner_internal::FormWindowSettings + + None + 없음 + + + Device Profile: %1 + 장치 프로필: %1 + + + + qdesigner_internal::GridPanel + + Form + + + + Grid + 격자 + + + Visible + 보이기 + + + Grid &X + 격자 X 간격(&X) + + + Snap + 맞춤 + + + Reset + 초기화 + + + Grid &Y + 격자 Y 간격(&Y) + + + + qdesigner_internal::GroupBoxTaskMenu + + Change title... + 제목 변경... + + + + qdesigner_internal::HtmlTextEdit + + Insert HTML entity + HTML 엔티티 삽입 + + + + qdesigner_internal::IconSelector + + The pixmap file '%1' cannot be read. + 픽스맵 파일 '%1'을(를) 읽을 수 없습니다. + + + The file '%1' does not appear to be a valid pixmap file: %2 + 파일 '%1'은(는) 올바른 픽스맵 파일 같지 않습니다: %2 + + + The file '%1' could not be read: %2 + 파일 '%1'을(를) 읽을 수 없습니다: %2 + + + Choose a Pixmap + 픽스맵 선택 + + + Pixmap Read Error + 픽스맵 읽기 오류 + + + ... + ... + + + Normal Off + 일반 꺼짐 + + + Normal On + 일반 켜짐 + + + Disabled Off + 사용 불가능 꺼짐 + + + Disabled On + 사용 불가능 켜짐 + + + Active Off + 활성 꺼짐 + + + Active On + 활성 켜짐 + + + Selected Off + 선택 꺼짐 + + + Selected On + 선택 켜짐 + + + Choose Resource... + 리소스 선택... + + + Choose File... + 파일 선택... + + + Reset + 초기화 + + + Reset All + 모두 초기화 + + + + qdesigner_internal::ItemListEditor + + Items List + 항목 목록 + + + New Item + 새 항목 + + + &New + 새로 만들기(&N) + + + Delete Item + 항목 삭제 + + + &Delete + 삭제(&D) + + + Move Item Up + 항목 위로 이동 + + + U + U + + + Move Item Down + 항목 아래로 이동 + + + D + D + + + Properties &>> + 속성 &>> + + + Properties &<< + 속성 &<< + + + + qdesigner_internal::LabelTaskMenu + + Change rich text... + 서식있는 텍스트 바꾸기... + + + Change plain text... + 일반 텍스트 바꾸기... + + + + qdesigner_internal::LanguageResourceDialog + + Choose Resource + 리소스 선택 + + + + qdesigner_internal::LineEditTaskMenu + + Change text... + 텍스트 선택... + + + + qdesigner_internal::ListWidgetEditor + + New Item + 새 항목 + + + Edit List Widget + 목록 위젯 편집 + + + Edit Combobox + 콤보 상자 편집 + + + + qdesigner_internal::ListWidgetTaskMenu + + Edit Items... + 항목 편집... + + + Change List Contents + 목록 내용 변경 + + + + qdesigner_internal::MdiContainerWidgetTaskMenu + + Next Subwindow + 다음 하위 창 + + + Previous Subwindow + 이전 하위 창 + + + Tile + 바둑판식 배열 + + + Cascade + 계단식 배열 + + + + qdesigner_internal::MenuTaskMenu + + Remove + 삭제 + + + + qdesigner_internal::MorphMenu + + Morph into + 다음으로 변형 + + + + qdesigner_internal::NewActionDialog + + New Action... + 새 동작... + + + &Text: + 텍스트(&T): + + + Object &name: + 객체 이름(&N): + + + &Icon: + 아이콘(&I): + + + Shortcut: + 단축키: + + + Checkable: + 선택 가능: + + + ToolTip: + 풍선 도움말: + + + ... + ... + + + + qdesigner_internal::NewDynamicPropertyDialog + + Create Dynamic Property + 동적 속성 만들기 + + + Property Name + 속성 이름 + + + horizontalSpacer + horizontalSpacer + + + Property Type + 속성 형식 + + + Set Property Name + 속성 이름 설정 + + + The current object already has a property named '%1'. +Please select another, unique one. + 현재 객체에 속성 '%1'이(가) 있습니다. +다른 이름을 지정하십시오. + + + The '_q_' prefix is reserved for the Qt library. +Please select another name. + '_q_' 접두사는 Qt 라이브러리에서 사용하기 위해 예약되어 있습니다. +다른 이름을 사용하십시오. + + + + qdesigner_internal::NewFormWidget + + 0 + 0 + + + Choose a template for a preview + 미리 볼 템플릿 선택 + + + Embedded Design + 임베디드 디자인 + + + Device: + 장치: + + + Screen Size: + 화면 크기: + + + Default size + 기본 크기 + + + QVGA portrait (240x320) + QVGA 세로 (240x320) + + + QVGA landscape (320x240) + QVGA 가로 (320x240) + + + VGA portrait (480x640) + VGA 세로 (480x640) + + + VGA landscape (640x480) + VGA 가로 (640x480) + + + Widgets + New Form Dialog Categories + 위젯 + + + Custom Widgets + 사용자 정의 위젯 + + + None + 없음 + + + Error loading form + 폼 불러오는 중 오류 발생 + + + Unable to open the form template file '%1': %2 + 폼 템플릿 파일 '%1'을(를) 열 수 없음: %2 + + + Internal error: No template selected. + 내부 오류: 템플릿이 선택되지 않았습니다. + + + + qdesigner_internal::NewPromotedClassPanel + + Add + 추가 + + + New Promoted Class + 새 승격된 클래스 + + + Base class name: + 기반 클래스 이름: + + + Promoted class name: + 승격된 클래스 이름: + + + Header file: + 헤더 파일: + + + Global include + 전역 포함 + + + Reset + 초기화 + + + + qdesigner_internal::ObjectInspector + + Change Current Page + 현재 쪽 변경 + + + &Find in Text... + 텍스트에서 찾기(&F)... + + + + qdesigner_internal::OrderDialog + + Change Page Order + 쪽 순서 변경 + + + Page Order + 쪽 순서 + + + Move page up + 쪽 위로 이동 + + + Move page down + 쪽 아래로 이동 + + + Index %1 (%2) + 인덱스 %1 (%2) + + + %1 %2 + %1 %2 + + + + qdesigner_internal::PaletteEditor + + Edit Palette + 팔레트 편집 + + + Tune Palette + 팔레트 조정 + + + Show Details + 팔레트 직접 편집 + + + Compute Details + 팔레트 자동 생성 + + + Quick + 빠른 설정 + + + Preview + 미리 보기 + + + Disabled + 사용 불가능 + + + Inactive + 비활성 + + + Active + 활성 + + + + qdesigner_internal::PaletteEditorButton + + Change Palette + 팔레트 변경 + + + + qdesigner_internal::PaletteModel + + Color Role + 색상 역할 + + + Active + 활성 + + + Inactive + 비활성 + + + Disabled + 사용 불가능 + + + + qdesigner_internal::PixmapEditor + + Choose Resource... + 리소스 선택... + + + Choose File... + 파일 선택... + + + Copy Path + 경로 복사 + + + Paste Path + 경로 붙여넣기 + + + ... + ... + + + + qdesigner_internal::PlainTextEditorDialog + + Edit text + 텍스트 편집 + + + + qdesigner_internal::PluginDialog + + Components + 구성 요소 + + + Plugin Information + 플러그인 정보 + + + Refresh + 새로 고침 + + + Scan for newly installed custom widget plugins. + 새로 설치된 사용자 정의 위젯 플러그인을 검사합니다. + + + Loaded Plugins + 불러온 플러그인 + + + Failed Plugins + 실패한 플러그인 + + + Qt Designer couldn't find any plugins + Qt Designer에서 플러그인을 찾을 수 없습니다 + + + Qt Designer found the following plugins + Qt Designer에서 다음 플러그인을 찾았습니다 + + + New custom widget plugins have been found. + 새 사용자 정의 위젯 플러그인을 찾았습니다. + + + + qdesigner_internal::PreviewActionGroup + + %1 Style + %1 스타일 + + + + qdesigner_internal::PreviewConfigurationWidget + + Default + 기본값 + + + None + 없음 + + + Browse... + 찾아보기... + + + Load Custom Device Skin + 사용자 정의 장치 스킨 불러오기 + + + All QVFB Skins (*.%1) + 모든 QVFB 스킨 (*.%1) + + + %1 - Duplicate Skin + %1 - 중복된 스킨 + + + The skin '%1' already exists. + 스킨 '%1'이(가) 이미 존재합니다. + + + %1 - Error + %1 - 오류 + + + %1 is not a valid skin directory: +%2 + %1은(는) 올바른 스킨 디렉터리가 아닙니다: +%2 + + + + qdesigner_internal::PreviewDeviceSkin + + &Portrait + 세로(&P) + + + Landscape (&CCW) + Rotate form preview counter-clockwise + 가로 (반시계방향)(&C) + + + &Landscape (CW) + Rotate form preview clockwise + 가로 (시계방향)(&L) + + + &Close + 닫기(&C) + + + + qdesigner_internal::PreviewManager + + %1 - [Preview] + %1 - [미리 보기] + + + + qdesigner_internal::PreviewMdiArea + + The moose in the noose +ate the goose who was loose. + Palette editor background + 키스의 고유 조건은 입술끼리 +만나야 되고 특별한 요령은 필요치 않다. + + + + qdesigner_internal::PreviewWidget + + Preview Window + 미리 보기 창 + + + LineEdit + 라인 편집기 + + + ComboBox + 콤보 상자 + + + PushButton + 누름 단추 + + + ButtonGroup2 + 단추 그룹 2 + + + CheckBox1 + 체크 상자 1 + + + CheckBox2 + 체크 상자 2 + + + ButtonGroup + 단추 그룹 + + + RadioButton1 + 라디오 단추 1 + + + RadioButton2 + 라디오 단추 2 + + + RadioButton3 + 라디오 단추 3 + + + + qdesigner_internal::PromotionModel + + Name + 이름 + + + Header file + 헤더 파일 + + + Global include + 전역 포함 + + + Usage + 사용 여부 + + + + qdesigner_internal::PromotionTaskMenu + + Promoted widgets... + 승격된 위젯... + + + Promote to ... + 다음으로 승격... + + + Change signals/slots... + 시그널/슬롯 변경... + + + Promote to + 다음으로 승격 + + + Demote to %1 + %1(으)로 승격 해제 + + + + qdesigner_internal::PropertyEditor + + Add Dynamic Property... + 동적 속성 추가... + + + Remove Dynamic Property + 동적 속성 삭제 + + + Sorting + 정렬 + + + Color Groups + 색 그룹 + + + Tree View + 트리 보기 + + + Drop Down Button View + 드롭다운 단추 보기 + + + String... + 문자열... + + + Bool... + 참/거짓... + + + Other... + 기타... + + + Configure Property Editor + 속성 편집기 설정 + + + Object: %1 +Class: %2 + 객체: %1 +클래스: %2 + + + + qdesigner_internal::PropertyLineEdit + + Insert line break + 줄 띄우기 + + + + qdesigner_internal::QDesignerPromotionDialog + + Promoted Widgets + 승격된 위젯 + + + Promoted Classes + 승격된 클래스 + + + Promote + 승격 + + + Change signals/slots... + 시그널/슬롯 변경... + + + %1 - Error + %1 - 오류 + + + + qdesigner_internal::QDesignerResource + + Loading qrc file + qrc 파일 불러오는 중 + + + The specified qrc file <p><b>%1</b></p><p>could not be found. Do you want to update the file location?</p> + 지정한 qrc 파일 <p><b>%1</b></p><p>을(를) 찾을 수 없습니다. 파일 위치를 변경하시겠습니까?</p> + + + New location for %1 + %1의 새로운 위치 + + + Resource files (*.qrc) + 리소스 파일 (*.qrc) + + + + qdesigner_internal::QDesignerTaskMenu + + Change objectName... + objectName 바꾸기... + + + Change toolTip... + toolTip 바꾸기... + + + Change whatsThis... + whatsThis 바꾸기... + + + Change styleSheet... + styleSheet 바꾸기... + + + Create Menu Bar + 메뉴 표시줄 생성 + + + Add Tool Bar + 도구 모음 추가 + + + Create Status Bar + 상태 표시줄 생성 + + + Remove Status Bar + 상태 표시줄 삭제 + + + Change script... + 스크립트 변경... + + + Change signals/slots... + 시그널/슬롯 변경... + + + Go to slot... + 슬롯으로 이동... + + + Size Constraints + 크기 제한 + + + Set Minimum Width + 최소 너비 설정 + + + Set Minimum Height + 최소 높이 설정 + + + Set Minimum Size + 최소 크기 설정 + + + Set Maximum Width + 최대 너비 설정 + + + Set Maximum Height + 최대 높이 설정 + + + Set Maximum Size + 최대 크기 설정 + + + Edit ToolTip + 풍선 도움말 편집 + + + Edit WhatsThis + 컨텍스트 도움말 편집 + + + no signals available + 사용 가능한 시그널 없음 + + + Set size constraint on %n widget(s) + + 위젯 %n개의 크기 제한 설정 + + + + + qdesigner_internal::QDesignerWidgetBox + + Unexpected element <%1> + 예상하지 못한 원소 <%1> + + + A parse error occurred at line %1, column %2 of the XML code specified for the widget %3: %4 +%5 + 위젯 %3 XML 코드의 %1번째 줄, %2번째 칸에서 처리 오류 발생: %4 +%5 + + + The XML code specified for the widget %1 does not contain any widget elements. +%2 + 위젯 %1의 XML 코드에 widget 원소가 없습니다. +%2 + + + An error has been encountered at line %1 of %2: %3 + %2의 %1번째 줄에서 오류 발생: %3 + + + Unexpected element <%1> encountered when parsing for <widget> or <ui> + <widget>이나 <ui>를 처리하는 중 예상하지 못한 원소 <%1>을(를) 만남 + + + Unexpected end of file encountered when parsing widgets. + 위젯을 처리하는 중 예상하지 못한 곳에서 파일이 끝났습니다. + + + A widget element could not be found. + widget 원소를 찾을 수 없습니다. + + + + qdesigner_internal::QtGradientStopsController + + H + H + + + S + S + + + V + V + + + Hue + 명도 + + + Sat + 채도 + + + Val + 휘도 + + + Saturation + 채도 + + + Value + 휘도 + + + R + R + + + G + G + + + B + B + + + Red + 빨강 + + + Green + 녹색 + + + Blue + 파랑 + + + + qdesigner_internal::RichTextEditorDialog + + Edit text + 텍스트 편집 + + + Rich Text + 서식있는 텍스트 + + + Source + 원본 + + + &OK + 확인(&O) + + + &Cancel + 취소(&C) + + + + qdesigner_internal::RichTextEditorToolBar + + Bold + 굵게 + + + CTRL+B + CTRL+B + + + Italic + 기울임꼴 + + + CTRL+I + CTRL+I + + + Underline + 밑줄 + + + CTRL+U + CTRL+U + + + Left Align + 왼쪽 정렬 + + + Center + 가운데 정렬 + + + Right Align + 오른쪽 정렬 + + + Justify + 양쪽 맞춤 + + + Superscript + 위 첨자 + + + Subscript + 아래 첨자 + + + Insert &Link + 링크 삽입 (&L) + + + Insert &Image + 그림 삽입(&I) + + + + qdesigner_internal::ScriptDialog + + Edit script + 스크립트 편집 + + + <html>Enter a Qt Script snippet to be executed while loading the form.<br>The widget and its children are accessible via the variables <i>widget</i> and <i>childWidgets</i>, respectively. + <html>폼을 불러오는 동안 실행할 Qt 스크립트를 입력하십시오.<br>위젯과 자식 위젯은 각각 <i>widget</i>과 <i>childWidgets</i> 변수로 접근할 수 있습니다. + + + Syntax error + 문법 오류 + + + + qdesigner_internal::ScriptErrorDialog + + Script errors + 스크립트 오류 + + + + qdesigner_internal::SignalSlotDialog + + There is already a slot with the signature '%1'. + 형식이 '%1'인 슬롯이 이미 존재합니다. + + + There is already a signal with the signature '%1'. + 형식이 '%1'인 시그널이 이미 존재합니다. + + + %1 - Duplicate Signature + %1 - 중복된 형식 + + + Signals/Slots of %1 + %1의 시그널/슬롯 + + + + qdesigner_internal::SignalSlotEditorPlugin + + Edit Signals/Slots + 시그널/슬롯 편집 + + + F4 + F4 + + + + qdesigner_internal::SignalSlotEditorTool + + Edit Signals/Slots + 시그널/슬롯 편집 + + + + qdesigner_internal::StatusBarTaskMenu + + Remove + 삭제 + + + + qdesigner_internal::StringListEditorButton + + Change String List + 문자열 목록 변경 + + + + qdesigner_internal::StyleSheetEditorDialog + + Valid Style Sheet + 올바른 스타일시트 + + + Add Resource... + 리소스 추가... + + + Add Gradient... + 그라데이션 추가... + + + Add Color... + 색 추가... + + + Add Font... + 글꼴 추가... + + + Edit Style Sheet + 스타일시트 편집 + + + Invalid Style Sheet + 잘못된 스타일시트 + + + + qdesigner_internal::TabOrderEditor + + Start from Here + 이 번호로 설정 + + + Restart + 1번부터 설정 + + + Tab Order List... + 탭 순서 목록... + + + Tab Order List + 탭 순서 목록 + + + Tab Order + 탭 순서 + + + + qdesigner_internal::TabOrderEditorPlugin + + Edit Tab Order + 탭 순서 편집 + + + + qdesigner_internal::TabOrderEditorTool + + Edit Tab Order + 탭 순서 편집 + + + + qdesigner_internal::TableWidgetEditor + + Edit Table Widget + 표 위젯 편집 + + + &Items + 항목(&I) + + + Table Items + 표 항목 + + + Properties &>> + 속성 &>> + + + New Column + 새 행 + + + New Row + 새 열 + + + &Columns + 행(&C) + + + &Rows + 열(&R) + + + Properties &<< + 속성 &<< + + + + qdesigner_internal::TableWidgetTaskMenu + + Edit Items... + 항목 편집... + + + + qdesigner_internal::TemplateOptionsWidget + + Form + + + + Additional Template Paths + 추가 템플릿 경로 + + + ... + ... + + + Pick a directory to save templates in + 템플릿을 저장할 디렉터리를 지정하십시오 + + + + qdesigner_internal::TextEditTaskMenu + + Edit HTML + HTML 편집 + + + Change HTML... + HTML 바꾸기... + + + Edit Text + 텍스트 편집 + + + Change Plain Text... + 일반 텍스트 바꾸기... + + + + qdesigner_internal::TextEditor + + Choose Resource... + 리소스 선택... + + + Choose File... + 파일 선택... + + + ... + ... + + + Choose a File + 파일 선택 + + + + qdesigner_internal::ToolBarEventFilter + + Insert Separator before '%1' + '%1' 앞에 구분자 삽입 + + + Append Separator + 구분자 덧붙이기 + + + Remove action '%1' + 동작 '%1' 삭제 + + + Remove Toolbar '%1' + 도구 모음 '%1' 삭제 + + + Insert Separator + 구분자 삽입 + + + + qdesigner_internal::TreeWidgetEditor + + Edit Tree Widget + 트리 위젯 편집 + + + &Items + 항목(&I) + + + Tree Items + 트리 항목 + + + 1 + 1 + + + New Item + 새 항목 + + + &New + 새로 만들기(&N) + + + New Subitem + 새 하위 항목 + + + New &Subitem + 새 하위 항목(&S) + + + Delete Item + 항목 삭제 + + + &Delete + 삭제(&D) + + + Move Item Left (before Parent Item) + 항목 왼쪽으로 이동 (부모 항목 이전) + + + L + L + + + Move Item Right (as a First Subitem of the Next Sibling Item) + 항목 오른쪽으로 이동 (다음 자식 항목의 첫 하위 항목으로) + + + R + R + + + Move Item Up + 항목 위로 이동 + + + U + U + + + Move Item Down + 항목 아래로 이동 + + + D + D + + + Properties &>> + 속성 &>> + + + New Column + 새 행 + + + &Columns + 행(&C) + + + Per column properties + 행별 속성 + + + Common properties + 공통 속성 + + + Properties &<< + 속성 &<< + + + + qdesigner_internal::TreeWidgetTaskMenu + + Edit Items... + 항목 편집... + + + + qdesigner_internal::WidgetBox + + Warning: Widget creation failed in the widget box. This could be caused by invalid custom widget XML. + 경고: 위젯 상자에 위젯을 만들 수 없습니다. 잘못된 사용자 정의 위젯 XML 때문일 수 있습니다. + + + + qdesigner_internal::WidgetBoxTreeWidget + + Scratchpad + 연습장 + + + Custom Widgets + 사용자 정의 위젯 + + + Expand all + 모두 펴기 + + + Collapse all + 모두 접기 + + + List View + 목록 보기 + + + Icon View + 아이콘 보기 + + + Remove + 삭제 + + + Edit name + 이름 편집 + + + + qdesigner_internal::WidgetDataBase + + A custom widget plugin whose class name (%1) matches that of an existing class has been found. + 사용자 정의 위젯 플러그인의 전체 클래스 이름(%1)이 기존의 클래스 이름과 일치합니다. + + + + qdesigner_internal::WidgetEditorTool + + Edit Widgets + 위젯 편집 + + + + qdesigner_internal::WidgetFactory + + The custom widget factory registered for widgets of class %1 returned 0. + 클래스 %1인 위젯의 사용자 정의 위젯 팩터리에서 0을 반환하였습니다. + + + A class name mismatch occurred when creating a widget using the custom widget factory registered for widgets of class %1. It returned a widget of class %2. + 클래스 %1인 위젯에 등록된 사용자 정의 위젯 팩터리를 사용하여 위젯을 만드는 중 클래스 이름이 일치하지 않았습니다. 클래스 %2인 위젯을 반환하였습니다. + + + %1 Widget + %1 위젯 + + + The current page of the container '%1' (%2) could not be determined while creating a layout.This indicates an inconsistency in the ui-file, probably a layout being constructed on a container widget. + 레이아웃을 만드는 중 컨테이너 '%1' (%2)의 현재 쪽을 결정할 수 없습니다. UI 파일 내부에 불일치가 발생한 것 같으며, 컨테이너 위젯에 레이아웃이 만들어진 것 같습니다. + + + Attempt to add a layout to a widget '%1' (%2) which already has an unmanaged layout of type %3. +This indicates an inconsistency in the ui-file. + 관리되지 않은 %3 형식의 레이아웃이 있는 위젯 '%1' (%2)에 레이아웃을 추가할 수 없습니다. +UI 파일 내부에 불일치가 발생하였습니다. + + + Cannot create style '%1'. + 스타일 '%1'을(를) 만들 수 없습니다. + + + + qdesigner_internal::WizardContainerWidgetTaskMenu + + Next + 다음 + + + Back + 이전 + + + + qdesigner_internal::ZoomMenu + + %1 % + Zoom factor + %1 % + + + + qdesigner_internal::ZoomablePreviewDeviceSkin + + &Zoom + 확대/축소(&Z) + + + diff --git a/translations/linguist_ko.ts b/translations/linguist_ko.ts new file mode 100644 index 0000000..7545dbc --- /dev/null +++ b/translations/linguist_ko.ts @@ -0,0 +1,2500 @@ + + + + + AboutDialog + + Qt Linguist + Qt Linguist + + + + BatchTranslationDialog + + Qt Linguist - Batch Translation + Qt Linguist - 일괄 번역 + + + Options + 옵션 + + + Set translated entries to finished + 번역된 항목을 완료됨으로 표시 + + + Retranslate entries with existing translation + 이미 번역된 항목을 다시 번역 + + + Note that the modified entries will be reset to unfinished if 'Set translated entries to finished' above is unchecked + '번역된 항목을 완료됨으로 표시'를 선택하지 않으면 수정된 항목은 완료되지 않음으로 표시됩니다 + + + Translate also finished entries + 완료된 항목도 다시 번역 + + + Phrase book preference + 선호하는 단어장 + + + Move up + 위로 이동 + + + Move down + 아래로 이동 + + + The batch translator will search through the selected phrase books in the order given above + 일괄 번역 과정에서 위에 지정한 순서대로 단어장을 사용합니다 + + + &Run + 실행(&R) + + + Cancel + 취소 + + + Batch Translation of '%1' - Qt Linguist + '%1'의 일괄 번역 - Qt Linguist + + + Searching, please wait... + 검색 중, 기다려 주십시오... + + + &Cancel + 취소(&C) + + + Linguist batch translator + Linguist 일괄 번역 도구 + + + Batch translated %n entries + + 항목 %n개를 일괄 번역하였습니다 + + + + + DataModel + + <qt>Duplicate messages found in '%1': + <qt>'%1'에 중복된 메시지가 있음: + + + <p>[more duplicates omitted] + <p>[더 많은 항목 생략됨] + + + <p>* ID: %1 + <p>* ID: %1 + + + <p>* Context: %1<br>* Source: %2 + <p>* 컨텍스트: %1<br>* 원본: %2 + + + <br>* Comment: %3 + <br>* 설명: %3 + + + Linguist does not know the plural rules for '%1'. +Will assume a single universal form. + Linguist는 '%1'의 복수형을 알지 못합니다. +별도의 복수형이 없음을 가정합니다. + + + Cannot create '%2': %1 + '%2'을(를) 만들 수 없음: %1 + + + Universal Form + 단일 형태 + + + + ErrorsView + + Accelerator possibly superfluous in translation. + 번역된 메시지에 불필요한 가속기가 있습니다. + + + Accelerator possibly missing in translation. + 번역된 메시지에 가속기가 빠졌습니다. + + + Translation does not end with the same punctuation as the source text. + 번역된 메시지가 원본 메시지와 같은 문장 부호로 끝나지 않았습니다. + + + A phrase book suggestion for '%1' was ignored. + 단어장에서 제안한 '%1'을(를) 무시하였습니다. + + + Translation does not refer to the same place markers as in the source text. + 번역된 메시지와 원본 메시지의 자리 표시자가 일치하지 않습니다. + + + Translation does not contain the necessary %n place marker. + 필요한 %n개의 자리 표시자가 번역된 메시지에 포함되지 않았습니다. + + + Unknown error + 알 수 없는 오류 + + + + FindDialog + + Find + 찾기 + + + This window allows you to search for some text in the translation source file. + 번역 원본 파일의 텍스트를 찾을 수 있습니다. + + + &Find what: + 찾을 문자열(&F): + + + Type in the text to search for. + 찾을 문자열을 입력하십시오. + + + Options + 옵션 + + + Source texts are searched when checked. + 선택하면 원본 텍스트에서 찾습니다. + + + &Source texts + 원본 텍스트(&S) + + + Translations are searched when checked. + 선택하면 번역된 텍스트에서 찾습니다. + + + &Translations + 번역(&T) + + + Texts such as 'TeX' and 'tex' are considered as different when checked. + 선택하면 'TeX'와 'tex'를 다른 문자열로 취급합니다. + + + &Match case + 대소문자 구분(&M) + + + Comments and contexts are searched when checked. + 선택하면 설명과 컨텍스트에서 찾습니다. + + + &Comments + 설명(&C) + + + Ignore &accelerators + 가속기 무시(&A) + + + Click here to find the next occurrence of the text you typed in. + 입력한 텍스트가 다음에 등장하는 곳을 찾습니다. + + + Find Next + 다음 찾기 + + + Click here to close this window. + 이 창을 닫습니다. + + + Cancel + 취소 + + + + Choose Edit|Find from the menu bar or press Ctrl+F to pop up the Find dialog + + + + + FormMultiWidget + + Alt+Delete + translate, but don't change + Alt+Delete + + + Shift+Alt+Insert + translate, but don't change + Shift+Alt+Insert + + + Alt+Insert + translate, but don't change + Alt+Insert + + + Confirmation - Qt Linguist + 확인 - Qt Linguist + + + Delete non-empty length variant? + 내용이 있는 길이가 다른 형태를 삭제하시겠습니까? + + + + LConvert + + +Usage: + lconvert [options] <infile> [<infile>...] + +lconvert is part of Qt's Linguist tool chain. It can be used as a +stand-alone tool to convert and filter translation data files. +The following file formats are supported: + +%1 +If multiple input files are specified, they are merged with +translations from later files taking precedence. + +Options: + -h + --help Display this information and exit. + + -i <infile> + --input-file <infile> + Specify input file. Use if <infile> might start with a dash. + This option can be used several times to merge inputs. + May be '-' (standard input) for use in a pipe. + + -o <outfile> + --output-file <outfile> + Specify output file. Default is '-' (standard output). + + -if <informat> + --input-format <format> + Specify input format for subsequent <infile>s. + The format is auto-detected from the file name and defaults to 'ts'. + + -of <outformat> + --output-format <outformat> + Specify output format. See -if. + + --input-codec <codec> + Specify encoding for QM and PO input files. Default is 'Latin1' + for QM and 'UTF-8' for PO files. UTF-8 is always tried as well for + QM, corresponding to the possible use of the trUtf8() function. + + --output-codec <codec> + Specify encoding for PO output files. Default is 'UTF-8'. + + --drop-tags <regexp> + Drop named extra tags when writing TS or XLIFF files. + May be specified repeatedly. + + --drop-translations + Drop existing translations and reset the status to 'unfinished'. + Note: this implies --no-obsolete. + + --source-language <language>[_<region>] + Specify/override the language of the source strings. Defaults to + POSIX if not specified and the file does not name it yet. + + --target-language <language>[_<region>] + Specify/override the language of the translation. + The target language is guessed from the file name if this option + is not specified and the file contents name no language yet. + + --no-obsolete + Drop obsolete messages. + + --no-finished + Drop finished messages. + + --sort-contexts + Sort contexts in output TS file alphabetically. + + --locations {absolute|relative|none} + Override how source code references are saved in TS files. + Default is absolute. + + --no-ui-lines + Drop line numbers from references to UI files. + + --verbose + be a bit more verbose + +Long options can be specified with only one leading dash, too. + +Return value: + 0 on success + 1 on command line parse failures + 2 on read failures + 3 on write failures + + +사용 방법: + lconvert [옵션] <infile> [<infile>...] + +lconvert는 Qt Linguist 도구 모음의 일부입니다. 번역 데이터 +파일을 변환하고 처리하는 데 사용할 수 있습니다. +다음 파일 형식을 지원합니다: + +%1 +여러 개의 입력 파일을 지정하면, 나중에 지정한 파일에 +있는 내용을 우선으로 합칩니다. + +옵션: + -h + --help 이 정보를 표시하고 끝냅니다. + + -i <infile> + --input-file <infile> + 입력 파일을 지정합니다. <infile>이 이음표(-)로 시작한다면 + 사용하십시오. 여러 입력 파일을 합치려면 여러 번 사용할 + 수 있습니다. 파이프 내부에서 사용하려면 '-'를 사용하십시오. + + -o <outfile> + --output-file <outfile> + 출력 파일을 지정합니다. 기본값은 '-'(표준 출력)입니다. + + -if <informat> + --input-format <format> + 입력 파일 <infile> 바로 앞에 붙이며, 입력 파일의 형식을 지정합니다. + 파일 이름에서 형식을 자동으로 식별하며, 기본값은 'ts'입니다. + + -of <outformat> + --output-format <outformat> + 출력 형식을 지정합니다. -if를 참고하십시오. + + --input-codec <codec> + QM과 PO 입력 파일의 인코딩을 지정합니다. QM 파일의 기본값은 + 'Latin1'이며, PO 파일의 기본값은 'UTF-8'입니다. trUtf8() 함수를 + 사용했을 수도 있기 때문에 QM 파일에서도 UTF-8을 시도합니다. + + --output-codec <codec> + PO 출력 파일의 인코딩을 지정합니다. 기본값은 'UTF-8'입니다. + + --drop-tags <regexp> + TS나 XLIFF 파일을 쓸 때 추가 태그를 기록하지 않습니다. + 여러 번 사용할 수 있습니다. + + --drop-translations + 이미 있는 번역을 삭제하며 상태를 '완료되지 않음'으로 초기화합니다. + 알림: --no-obsolete 옵션을 암시적으로 지정합니다. + + --source-language <language>[_<region>] + 원본 문자열의 언어를 (재)지정합니다. 파일 이름에서 언어를 알 수 + 없거나 지정되지 않았을 때의 기본값은 POSIX입니다. + + --target-language <language>[_<region>] + 번역물의 언어를 (재)지정합니다. 이 옵션을 지정하지 않았고 + 파일 내용에 언어를 지정하지 않았으면 파일 이름에서 + 대상 언어를 추정합니다. + + --no-obsolete + 오래된 메시지를 삭제합니다. + + --no-finished + 완료되지 않은 메시지를 삭제합니다. + + --sort-contexts + 출력 TS 파일의 컨텍스트를 가나다순으로 정렬합니다. + + --locations {absolute|relative|none} + 원본 코드 참조를 TS 파일에 저장할 법을 지정합니다. + 기본값은 absolute입니다. + + --no-ui-lines + UI 파일 참조에서 줄 번호를 삭제합니다. + + --verbose + 더 자세한 메시지를 출력합니다. + +긴 옵션을 지정할 때에는 이음표 하나만 사용할 수 있습니다. + +반환값: + 0: 성공 + 1: 명령행 인자 처리 오류 + 2: 읽기 오류 + 3: 쓰기 오류 + + + + + LRelease + + Usage: + lrelease [options] project-file + lrelease [options] ts-files [-qm qm-file] + +lrelease is part of Qt's Linguist tool chain. It can be used as a +stand-alone tool to convert XML-based translations files in the TS +format into the 'compiled' QM format used by QTranslator objects. + +Options: + -help Display this information and exit + -idbased + Use IDs instead of source strings for message keying + -compress + Compress the QM files + -nounfinished + Do not include unfinished translations + -removeidentical + If the translated text is the same as + the source text, do not include the message + -markuntranslated <prefix> + If a message has no real translation, use the source text + prefixed with the given string instead + -silent + Do not explain what is being done + -version + Display the version of lrelease and exit + + 사용 방법: + lrelease [옵션] project-file + lrelease [옵션] ts-files [-qm qm-file] + +lrelease는 Qt Linguist 도구 모음의 일부입니다. TS 형식으로 되어 있는 +XML 기반 번역물은 QTranslator에서 사용할 수 있는 '컴파일된' QM +형식으로 변환하는 독립 실행 가능한 도구입니다. + +옵션: + -help 이 정보를 표시하고 끝냅니다. + -idbased + 메시지 키로 원본 문자열 대신 ID를 사용합니다. + -compress + QM 파일을 압축합니다. + -nounfinished + 완료되지 않은 번역을 포함하지 않습니다. + -removeidentical + 원문과 번역문이 같으면 메시지를 포함하지 않습니다. + -markuntranslated <prefix> + 메시지가 번역되지 않았으면 원본 문자열 앞에 + <prefix>를 붙인 것을 번역문 대신 사용합니다. + -silent + 진행 상황을 표시하지 않습니다. + -version + lrelease 버전을 표시하고 끝냅니다 + + + + lrelease error: %1 + lrelease 오류: %1 + + + Updating '%1'... + + '%1' 업데이트 중... + + + + Removing translations equal to source text in '%1'... + + '%1'의 원문과 동일한 번역문 삭제 중... + + + + lrelease error: cannot create '%1': %2 + + lrelease 오류: '%1'을(를) 만들 수 없음: %2 + + + + lrelease error: cannot save '%1': %2 + lrelease 오류: '%1'을(를) 저장할 수 없음: %2 + + + lrelease version %1 + + lrelease 버전 %1 + + + + lrelease error: cannot read project file '%1'. + + lrelease 오류: 프로젝트 파일 '%1'을(를) 읽을 수 없습니다. + + + lrelease error: cannot process project file '%1'. + + lrelease 오류: 프로젝트 파일 '%1'을(를) 처리할 수 없습니다. + + + + lrelease warning: Met no 'TRANSLATIONS' entry in project file '%1' + + lrelease 경고: 프로젝트 파일 '%1'에 'TRANSLATIONS' 항목이 없음 + + + + Dropped %n message(s) which had no ID. + + ID가 없는 메시지 %n개를 삭제하였습니다. + + + + Excess context/disambiguation dropped from %n message(s). + + 메시지 %n개에서 불필요한 컨텍스트/동음이의 정보를 삭제하였습니다. + + + + Generated %n translation(s) (%1 finished and %2 unfinished) + + %n개의 번역 생성됨 (%1개 완료됨, %2개 완료되지 않음) + + + + Ignored %n untranslated source text(s) + + %n개의 번역되지 않은 원문 무시함 + + + + + LUpdate + + Parenthesis/bracket/brace mismatch between #if and #else branches; using #if branch + + #if와 #else 분기 사이에서 소/중/대괄호가 일치하지 않음. #if 분기를 사용함 + + + + Parenthesis/brace mismatch between #if and #else branches; using #if branch + + #if와 #else 분기 사이에서 소/중괄호가 일치하지 않음. #if 분기를 사용함 + + + + Unterminated C++ comment + + C++ 주석이 종료되지 않음 + + + + Unterminated C++ string + + C++ 문자열이 종료되지 않음 + + + + Excess closing brace in C++ code (or abuse of the C++ preprocessor) + + C++ 코드에 불필요한 닫는 중괄호가 있음(또는 C++ 전처리기의 잘못된 사용) + + + + Excess closing parenthesis in C++ code (or abuse of the C++ preprocessor) + + C++ 코드에 불필요한 닫는 소괄호가 있음(또는 C++ 전처리기의 잘못된 사용) + + + + Excess closing bracket in C++ code (or abuse of the C++ preprocessor) + + C++ 코드에 불필요한 닫는 대괄호가 있음(또는 C++ 전처리기의 잘못된 사용) + + + + circular inclusion of %1 + + %1이(가) 재귀적으로 포함됨 + + + + Cannot open %1: %2 + + %1을(를) 열 수 없음: %2 + + + + //% cannot be used with tr() / QT_TR_NOOP(). Ignoring + + //%는 tr()/QT_TR_NOOP()와 같이 사용할 수 없음. 무시함 + + + + Qualifying with unknown namespace/class %1::%2 + + 알 수 없는 네임스페이스/클래스 %1::%2와(과) 일치함 + + + tr() cannot be called without context + + tr()은 컨텍스트 없이 호출될 수 없음 + + + + Class '%1' lacks Q_OBJECT macro + + 클래스 '%1'에 Q_OBJECT 매크로가 없음 + + + + It is not recommended to call tr() from within a constructor '%1::%2' + + 생성자 '%1::%2'에서 tr()을 호출하는 것은 권장하지 않음 + + + + //% cannot be used with translate() / QT_TRANSLATE_NOOP(). Ignoring + + //%는 translate()/QT_TR_NOOP()와 같이 사용할 수 없음. 무시함 + + + + //= cannot be used with qtTrId() / QT_TRID_NOOP(). Ignoring + + //=은 qtTrId()/QT_TRID_NOOP()와 같이 사용할 수 없음. 무시함 + + + + Unexpected character in meta string + + 메타 문자열에 예상하지 못한 글자가 있음 + + + + Unterminated meta string + + 메타 문자열이 종료되지 않음 + + + + Cannot invoke tr() like this + + tr()을 이렇게 호출할 수 없음 + + + + Discarding unconsumed meta data + + 사용되지 않은 메타데이터를 무시함 + + + + Unbalanced opening brace in C++ code (or abuse of the C++ preprocessor) + + C++ 코드의 여는 중괄호 쌍이 맞지 않음(또는 C++ 전처리기의 잘못된 사용) + + + + Unbalanced opening parenthesis in C++ code (or abuse of the C++ preprocessor) + + C++ 코드의 여는 소괄호 쌍이 맞지 않음(또는 C++ 전처리기의 잘못된 사용) + + + + Unbalanced opening bracket in C++ code (or abuse of the C++ preprocessor) + + C++ 코드의 여는 대괄호 쌍이 맞지 않음(또는 C++ 전처리기의 잘못된 사용) + + + + Cannot open %1: %2 + %1을(를) 열 수 없음: %2 + + + Unterminated Java comment. + + Java 주석이 종료되지 않았습니다. + + + + Invalid Unicode value. + + 유니코드 값이 잘못되었습니다. + + + + Unterminated string. + + 문자열이 종료되지 않았습니다. + + + + String used in translation can contain only literals concatenated with other literals, not expressions or numbers. + + 번역에 사용하는 문자열은 서로 다른 문자열끼리만 연결되어 있어야 하며, 표현식이나 숫자와는 연결할 수 없습니다. + + + + 'class' must be followed by a class name. + + 'class' 다음에는 클래스 이름이 와야 합니다. + + + + Excess closing brace. + + 불필요한 닫는 중괄호가 있습니다. + + + 'package' must be followed by package name. + + 'package' 다음에는 패키지 이름이 와야 합니다. + + + + Unbalanced opening brace. + + 여는 중괄호의 쌍이 맞지 않습니다. + + + + Unbalanced opening parenthesis. + + 여는 소괄호의 쌍이 맞지 않습니다. + + + + Usage: + lupdate [options] [project-file]... + lupdate [options] [source-file|path|@lst-file]... -ts ts-files|@lst-file + +lupdate is part of Qt's Linguist tool chain. It extracts translatable +messages from Qt UI files, C++, Java and JavaScript/QtScript source code. +Extracted messages are stored in textual translation source files (typically +Qt TS XML). New and modified messages can be merged into existing TS files. + +Options: + -help Display this information and exit. + -no-obsolete + Drop all obsolete strings. + -extensions <ext>[,<ext>]... + Process files with the given extensions only. + The extension list must be separated with commas, not with whitespace. + Default: '%1'. + -pluralonly + Only include plural form messages. + -silent + Do not explain what is being done. + -no-sort + Do not sort contexts in TS files. + -no-recursive + Do not recursively scan the following directories. + -recursive + Recursively scan the following directories (default). + -I <includepath> or -I<includepath> + Additional location to look for include files. + May be specified multiple times. + -locations {absolute|relative|none} + Specify/override how source code references are saved in TS files. + Default is absolute. + -no-ui-lines + Do not record line numbers in references to UI files. + -disable-heuristic {sametext|similartext|number} + Disable the named merge heuristic. Can be specified multiple times. + -pro <filename> + Name of a .pro file. Useful for files with .pro file syntax but + different file suffix. Projects are recursed into and merged. + -source-language <language>[_<region>] + Specify the language of the source strings for new files. + Defaults to POSIX if not specified. + -target-language <language>[_<region>] + Specify the language of the translations for new files. + Guessed from the file name if not specified. + -ts <ts-file>... + Specify the output file(s). This will override the TRANSLATIONS + and nullify the CODECFORTR from possibly specified project files. + -codecfortr <codec> + Specify the codec assumed for tr() calls. Effective only with -ts. + -version + Display the version of lupdate and exit. + @lst-file + Read additional file names (one per line) from lst-file. + + 사용 방법: + lupdate [옵션] [project-file]... + lupdate [옵션] [source-file|path|@lst-file]... -ts ts-files|@lst-file + +lupdate는 Qt Linguist 도구 모음의 일부입니다. Qt UI 파일, C++, +Java, JavaScript/QtScript 원본 코드에서 번역 가능한 문자열을 추출합니다. +추출한 메시지는 번역 원본 파일(대개의 경우 Qt TS XML)에 저장됩니다. +기존 TS 파일에 새로 추가되었거나 수정된 메시지를 추가할 수 있습니다. + +옵션: + -help 이 정보를 표시하고 끝냅니다. + -no-obsolete + 모든 오래된 문자열을 삭제합니다. + -extensions <ext>[,<ext>]... + 주어진 확장자를 가진 파일만 처리합니다. + 확장자 목록은 쉼표로 구분하며, 공백을 사용하면 안 됩니다. + 기본값: '%1'. + -pluralonly + 복수형 메시지만 포함합니다. + -silent + 진행 상황을 표시하지 않습니다. + -no-sort + TS 파일의 컨텍스트를 정렬하지 않습니다. + -no-recursive + 하위 디렉터리를 재귀적으로 탐색하지 않습니다. + -recursive + 하위 디렉터리를 재귀적으로 탐색합니다. (기본값) + -I <includepath> 또는 -I<includepath> + 포함할 파일을 찾을 추가 경로입니다. + 여러 번 사용할 수 있습니다. + -locations {absolute|relative|none} + TS 파일에 원본 코드 위치를 저장할 방법을 (재)지정합니다. + 기본값은 absolute(절대 위치)입니다. + -no-ui-lines + UI 파일을 참조할 때 줄 번호를 기록하지 않습니다. + -disable-heuristic {sametext|similartext|number} + 지정한 메시지 휴리스틱을 사용하지 않습니다. + 여러 번 사용할 수 있습니다. + -pro <filename> + .pro 파일 이름입니다. .pro 파일 문법을 사용하지만 확장자가 + .pro가 아닌 경우에 사용하십시오. 재귀적으로 프로젝트를 + 탐색하며 합칩니다. + -source-language <language>[_<region>] + 새 파일의 원문 언어를 지정합니다. + 지정하지 않으면 POSIX를 사용합니다. + -target-language <language>[_<region>] + 새 파일의 번역문 언어를 지정합니다. + 지정하지 않으면 파일 이름에서 추측합니다. + -ts <ts-file>... + 출력 파일을 지정합니다. TRANSLATIONS를 다시 지정하며 + 프로젝트 파일에서 지정했을 수도 있는 CODECFORTR을 + 무효화합니다. + -codecfortr <codec> + tr() 함수에 사용하는 코덱을 지정합니다. + -ts 옵션과 같이 사용할 때만 유효합니다. + -version + lupdate 버전을 표시하고 끝냅니다. + @lst-file + lst-file에서 추가 파일 목록(한 줄에 하나)을 읽습니다. + + + + lupdate warning: Codec for tr() '%1' disagrees with existing file's codec '%2'. Expect trouble. + + lupdate 경고: tr()의 코덱 '%1'이(가) 파일의 코덱 '%2'와(과) 일치하지 않습니다. 내보낼 때 문제가 생길 수 있습니다. + + + + lupdate warning: Specified target language '%1' disagrees with existing file's language '%2'. Ignoring. + + lupdate 경고: 지정한 대상 언어 '%1'이(가) 파일의 언어 '%2'와(과) 다릅니다. 무시합니다. + + + + lupdate warning: Specified source language '%1' disagrees with existing file's language '%2'. Ignoring. + + lupdate 경고: 지정한 원본 언어 '%1'이(가) 파일의 언어 '%2'와(과) 다릅니다. 무시합니다. + + + + Updating '%1'... + + '%1' 업데이트 중... + + + + Stripping non plural forms in '%1'... + + '%1'의 단수형 삭제하는 중... + + + + lupdate warning: Codec for source '%1' is invalid. Falling back to codec for tr(). + + lupdate 경고: 원본 코덱 '%1'이(가) 올바르지 않습니다. tr()의 코덱을 사용합니다. + + + + lupdate warning: TS files from command line will override TRANSLATIONS in %1. + + lupdate 경고: 명령행으로 지정한 TS 파일이 %1의 TRANSLATIONS를 재정의합니다. + + + + lupdate warning: TS files from command line prevent recursing into %1. + + lupdate 경고: 명령행으로 지정한 TS 파일이 %1(으)로 재귀하는 것을 방지합니다. + + + + lupdate warning: no TS files specified. Only diagnostics will be produced for '%1'. + + lupdate 경고: TS 파일이 지정되지 않았습니다. '%1'의 검사만 진행됩니다. + + + + The option -target-language requires a parameter. + + --target-language 옵션에는 인자가 필요합니다. + + + + The option -source-language requires a parameter. + + --source-language 옵션에는 인자가 필요합니다. + + + + The option -disable-heuristic requires a parameter. + + --disable-heuristic 옵션에는 인자가 필요합니다. + + + + Invalid heuristic name passed to -disable-heuristic. + + --disable-heuristic에 잘못된 휴리스틱 이름이 전달되었습니다. + + + The option -locations requires a parameter. + + -locations 옵션에는 인자가 필요합니다. + + + + Invalid parameter passed to -locations. + + -locations 옵션에 잘못된 인자가 전달되었습니다. + + + + The -codecfortr option should be followed by a codec name. + + -codecfortr 옵션 다음에는 코덱 이름이 와야 합니다. + + + + The -extensions option should be followed by an extension list. + + -extensions 옵션 다음에는 확장자 목록이 와야 합니다. + + + + The -pro option should be followed by a filename of .pro file. + + -pro 옵션 다음에는 .pro 파일이 와야 합니다. + + + + The -I option should be followed by a path. + + -I 옵션 다음에는 경로가 와야 합니다. + + + + Unrecognized option '%1'. + + 알 수 없는 옵션 '%1'. + + + + lupdate error: List file '%1' is not readable. + + lupdate 오류: 목록 파일 '%1'을(를) 읽을 수 없습니다. + + + + lupdate warning: For some reason, '%1' is not writable. + + lupdate 경고: 파일 '%1'에 쓸 수 없습니다. + + + lupdate error: File '%1' has no recognized extension. + + lupdate 오류: 파일 '%1'의 확장자는 알려져 있지 않습니다. + + + + lupdate error: File '%1' does not exist. + + lupdate 오류: 파일 '%1'이(가) 없습니다. + + + + Scanning directory '%1'... + + 디렉터리 '%1' 검사 중... + + + + lupdate warning: -target-language usually only makes sense with exactly one TS file. + + lupdate 경고: -target-language는 TS 파일을 하나만 지정했을 때 적용됩니다. + + + + lupdate warning: -codecfortr has no effect without -ts. + + lupdate 경고: --codecfortr 옵션은 -ts 옵션을 지정해야 적용됩니다. + + + + lupdate warning: no TS files specified. Only diagnostics will be produced. + + lupdate 경고: TS 파일이 지정되지 않았습니다. 검사만 진행됩니다. + + + + lupdate error: Both project and source files / include paths specified. + + lupdate 오류: 프로젝트 파일과 원본 파일/포함 경로 둘 다를 지정하였습니다. + + + + Found %n source text(s) (%1 new and %2 already existing) + + + 원본 문자열 %n개 찾음 (새 문자열 %1개, 기존 문자열 %2개) + + + + + Removed %n obsolete entries + + + 오래된 항목 %n개 삭제됨 + + + + + Kept %n obsolete entries + + + 오래된 항목 %n개 보존됨 + + + + + Number heuristic provided %n translation(s) + + + 숫자 휴리스틱으로 %n개 번역됨 + + + + + Same-text heuristic provided %n translation(s) + + + 동일 텍스트 휴리스틱으로 %n개 번역됨 + + + + + Similar-text heuristic provided %n translation(s) + + + 비슷한 텍스트 휴리스틱으로 %n개 번역됨 + + + + + Illegal character + 잘못된 문자 + + + Unclosed string at end of line + 줄 끝에서 문자열이 닫히지 않았음 + + + Illegal escape squence + 잘못된 탈출 문자 + + + Illegal unicode escape sequence + 잘못된 유니코드 탈출 문자 + + + Unclosed comment at end of file + 파일 끝에서 주석이 닫히지 않았음 + + + Illegal syntax for exponential number + 지수 표기법이 잘못됨 + + + Identifier cannot start with numeric literal + 식별자는 숫자 리터럴로 시작할 수 없음 + + + Unterminated regular expression literal + 종료되지 않은 정규 표현식 리터럴 + + + //% cannot be used with %1(). Ignoring + + //%는 %1()와(과) 사용될 수 없음. 무시함 + + + + %1() requires at least two arguments. + + %1()에는 최소 2개의 인자가 필요합니다. + + + + %1(): both arguments must be literal strings. + + %1(): 두 인자는 문자열 리터럴이어야 합니다. + + + + %1() requires at least one argument. + + %1()에는 최소 1개의 인자가 필요합니다. + + + + %1(): text to translate must be a literal string. + + %1(): 번역할 텍스트는 문자열 리터럴이어야 합니다. + + + + //= cannot be used with %1(). Ignoring + + //=은 %1()와(과) 같이 사용할 수 없음. 무시함 + + + + %1(): identifier must be a literal string. + + %1(): 식별자는 문자열 리터럴이어야 합니다. + + + + Expected + Beginning of the string that contains comma-separated list of expected tokens + 예상한 토큰 + + + XML error: Parse error at line %1, column %2 (%3). + XML 오류: %1번째 줄, %2번째 칸에서 처리 오류 발생(%3). + + + Parse error in UI file + UI 파일 처리 오류 + + + + MainWindow + + MainWindow + MainWindow + + + &Phrases + 단어장(&P) + + + &Close Phrase Book + 단어장 닫기(&C) + + + &Edit Phrase Book + 단어장 편집(&E) + + + &Print Phrase Book + 단어장 인쇄(&P) + + + V&alidation + 검사(&A) + + + &View + 보기(&V) + + + Vie&ws + 보기(&W) + + + &Toolbars + 도구 모음(&T) + + + &Help + 도움말(&H) + + + &Translation + 번역(&T) + + + &File + 파일(&F) + + + Recently Opened &Files + 최근에 연 파일(&F) + + + &Edit + 편집(&E) + + + &Open... + 열기(&O)... + + + Open a Qt translation source file (TS file) for editing + 편집할 Qt 번역 원본 파일(TS 파일)을 엽니다 + + + Ctrl+O + Ctrl+O + + + E&xit + 끝내기(&X) + + + Close this window and exit. + 이 창을 닫고 종료합니다. + + + Ctrl+Q + Ctrl+Q + + + Save + 저장 + + + Save changes made to this Qt translation source file + Qt 번역 원본 파일을 저장합니다 + + + Save &As... + 다른 이름으로 저장(&A)... + + + Save As... + 다른 이름으로 저장... + + + Save changes made to this Qt translation source file into a new file. + 변경된 Qt 번역 원본 파일을 다른 이름으로 저장합니다. + + + Release + 배포 + + + Create a Qt message file suitable for released applications from the current message file. + 현재 메시지 파일을 프로그램에 사용할 수 있는 형태로 배포합니다. + + + &Print... + 인쇄(&P)... + + + Print a list of all the translation units in the current translation source file. + 번역 원본 파일에 있는 모든 번역 단위 목록을 인쇄합니다. + + + Ctrl+P + Ctrl+P + + + &Undo + 실행 취소(&U) + + + Undo the last editing operation performed on the current translation. + 현재 번역물에 실행한 마지막 작업을 취소합니다. + + + Ctrl+Z + Ctrl+Z + + + &Redo + 다시 실행(&R) + + + Redo an undone editing operation performed on the translation. + 마지막으로 취소한 작업을 다시 실행합니다. + + + Ctrl+Y + Ctrl+Y + + + Cu&t + 잘라내기(&T) + + + Copy the selected translation text to the clipboard and deletes it. + 선택한 텍스트를 클립보드로 복사하고 입력 창에서 삭제합니다. + + + Ctrl+X + Ctrl+X + + + &Copy + 복사(&C) + + + Copy the selected translation text to the clipboard. + 선택한 텍스트를 클립보드에 복사합니다. + + + Ctrl+C + Ctrl+C + + + &Paste + 붙여넣기(&P) + + + Paste the clipboard text into the translation. + 클립보드에 있는 텍스트를 붙여 넣습니다. + + + Ctrl+V + Ctrl+V + + + Select &All + 모두 선택(&A) + + + Select the whole translation text. + 모든 번역 메시지를 선택합니다. + + + Ctrl+A + Ctrl+A + + + &Find... + 찾기(&F)... + + + Search for some text in the translation source file. + 번역 원본 파일의 텍스트를 찾습니다. + + + Ctrl+F + Ctrl+F + + + Find &Next + 다음 찾기(&N) + + + Continue the search where it was left. + 입력한 문자열이 다음에 나오는 곳을 찾습니다. + + + F3 + F3 + + + &Prev Unfinished + 이전 미완료(&P) + + + Previous unfinished item + 이전 미완료 항목 + + + Move to the previous unfinished item. + 이전 미완료 항목으로 이동합니다. + + + Ctrl+K + Ctrl+K + + + &Next Unfinished + 다음 미완료(&N) + + + Next unfinished item + 다음 미완료 항목 + + + Move to the next unfinished item. + 다음 미완료 항목으로 이동합니다. + + + Ctrl+J + Ctrl+J + + + P&rev + 이전(&R) + + + Move to previous item + 이전 항목으로 이동 + + + Move to the previous item. + 이전 항목으로 이동합니다. + + + Ctrl+Shift+K + Ctrl+Shift+K + + + Ne&xt + 다음(&X) + + + Next item + 다음 항목 + + + Move to the next item. + 다음 항목으로 이동합니다. + + + Ctrl+Shift+J + Ctrl+Shift+J + + + &Done and Next + 완료 표시 후 다음(&D) + + + Mark item as done and move to the next unfinished item + 항목을 완료된 것으로 표시하고 다음 미완료 항목으로 이동 + + + Mark this item as done and move to the next unfinished item. + 항목을 완료된 것으로 표시하고 다음 미완료 항목으로 이동합니다. + + + Copy from source text + 원본 텍스트 복사 + + + Copies the source text into the translation field + 원본 텍스트를 번역문으로 복사 + + + Copies the source text into the translation field. + 원본 텍스트를 번역문으로 복사합니다. + + + Ctrl+B + Ctrl+B + + + &Accelerators + 가속기(&A) + + + Toggle the validity check of accelerators + 가속기 키 유효성 검사 활성화/비활성화 + + + Toggle the validity check of accelerators, i.e. whether the number of ampersands in the source and translation text is the same. If the check fails, a message is shown in the warnings window. + 가속기 키 검사를 켜거나 끕니다. 검사가 켜져 있으면 원문과 번역문의 & 기호 개수가 똑같은 지 검사합니다. 검사가 실패하면 경고 창에 메시지를 표시합니다. + + + &Ending Punctuation + 끝맺는 문장 부호(&E) + + + Toggle the validity check of ending punctuation + 끝맺는 문장 부호 유효성 검사 활성화/비활성화 + + + Toggle the validity check of ending punctuation. If the check fails, a message is shown in the warnings window. + 원문과 번역문의 끝맺는 문장 부호가 서로 같은지 검사합니다. 검사가 실패하면 경고 창에 메시지를 표시합니다. + + + &Phrase matches + 단어장 일치(&P) + + + Toggle checking that phrase suggestions are used + 단어장에서 제안한 단어 사용 여부 검사 활성화/비활성화 + + + Toggle checking that phrase suggestions are used. If the check fails, a message is shown in the warnings window. + 단어장에서 제안한 단어를 사용했는지 여부를 검사합니다. 검사가 실패하면 경고 창에 메시지를 표시합니다. + + + Place &Marker Matches + 자리 표시자 일치(&M) + + + Toggle the validity check of place markers + 자리 표시자 일치 검사 활성화/비활성화 + + + Toggle the validity check of place markers, i.e. whether %1, %2, ... are used consistently in the source text and translation text. If the check fails, a message is shown in the warnings window. + 원문과 번역문에 있는 %1, %2와 같은 자리 표시자가 올바르게 사용되었는지 검사합니다. 검사가 실패하면 경고 창에 메시지를 표시합니다. + + + &New Phrase Book... + 새 단어장(&N)... + + + Create a new phrase book. + 새 단어장을 만듭니다. + + + Ctrl+N + Ctrl+N + + + &Open Phrase Book... + 단어장 열기(&O)... + + + Open a phrase book to assist translation. + 번역을 돕는 단어장을 엽니다. + + + Ctrl+H + Ctrl+H + + + &Reset Sorting + 정렬 초기화(&R) + + + Sort the items back in the same order as in the message file. + 항목 정렬을 메시지 파일 순서로 초기화합니다. + + + &Display guesses + 추측 표시(&D) + + + Set whether or not to display translation guesses. + 번역 추측을 표시할 지 여부입니다. + + + &Statistics + 통계(&S) + + + Display translation statistics. + 번역 통계를 표시합니다. + + + &Manual + 도움말(&M) + + + F1 + F1 + + + About Qt Linguist + Qt Linguist 정보 + + + About Qt + Qt 정보 + + + Display information about the Qt toolkit by Nokia. + Qt 툴킷의 정보를 표시합니다. + + + &What's This? + 이것에 대한 설명(&W) + + + What's This? + 항목별 도움말 + + + Enter What's This? mode. + 항목별 도움말을 표시합니다. + + + Shift+F1 + Shift+F1 + + + &Search And Translate... + 찾아서 번역(&S)... + + + Replace the translation on all entries that matches the search source text. + 원본 텍스트가 찾을 텍스트와 일치하는 모든 항목을 찾아서 번역합니다. + + + &Batch Translation... + 일괄 번역(&B)... + + + Batch translate all entries using the information in the phrase books. + 단어장의 정보를 사용하여 일괄적으로 번역합니다. + + + Release As... + 다른 이름으로 배포... + + + Create a Qt message file suitable for released applications from the current message file. The filename will automatically be determined from the name of the TS file. + 현재 메시지 파일을 프로그램에 사용할 수 있는 형태로 배포합니다. 파일 이름은 TS 파일 이름에서 자동으로 정해집니다. + + + File + 파일 + + + Edit + 편집 + + + Translation + 번역 + + + Validation + 검사 + + + Help + 도움말 + + + Open/Refresh Form &Preview + 폼 미리보기 열기/새로 고침(&P) + + + Form Preview Tool + 폼 미리보기 도구 + + + F5 + F5 + + + Translation File &Settings... + 번역 파일 설정(&S)... + + + &Add to Phrase Book + 단어장에 추가(&A) + + + Ctrl+T + Ctrl+T + + + Open Read-O&nly... + 읽기 전용으로 열기(&N)... + + + &Save All + 모두 저장(&S) + + + Ctrl+S + Ctrl+S + + + &Release All + 모두 배포(&R) + + + Close + 닫기 + + + &Close All + 모두 닫기(&C) + + + Ctrl+W + Ctrl+W + + + Length Variants + 다른 길이 문자열 + + + + This is the application's main window. + + + + Source text + 원본 텍스트 + + + Index + 인덱스 + + + Context + 컨텍스트 + + + Items + 항목 + + + This panel lists the source contexts. + 이 패널은 원본 컨텍스트 목록입니다. + + + Strings + 문자열 + + + Phrases and guesses + 단어장과 추측 + + + Sources and Forms + 원본 코드와 폼 + + + Warnings + 경고 + + + MOD + status bar: file(s) modified + 수정됨 + + + Loading... + 불러오는 중... + + + Loading File - Qt Linguist + 파일 불러오기 - Qt Linguist + + + The file '%1' does not seem to be related to the currently open file(s) '%2'. + +Close the open file(s) first? + 파일 '%1'이(가) 현재 열려 있는 파일 '%2'와(과) 관련이 없는 것 같습니다. + +열려 있는 파일을 닫으시겠습니까? + + + The file '%1' does not seem to be related to the file '%2' which is being loaded as well. + +Skip loading the first named file? + 파일 '%1'이(가) 같이 열려고 하는 파일 '%2'와(과) 관련이 없는 것 같습니다. + +첫 번째 파일을 열지 않으시겠습니까? + + + %n translation unit(s) loaded. + + 번역 단위 %n개를 불러 왔습니다. + + + + Related files (%1);; + 관련된 파일 (%1);; + + + Open Translation Files + 번역 파일 열기 + + + File saved. + 파일이 저장되었습니다. + + + Qt message files for released applications (*.qm) +All files (*) + 배포된 프로그램을 위한 Qt 메시지 파일 (*.qm) +모든 파일 (*) + + + File created. + 파일을 생성하였습니다. + + + Printing... + 인쇄 중... + + + Context: %1 + 컨텍스트: %1 + + + finished + 완료됨 + + + unresolved + 해결되지 않음 + + + obsolete + 오래됨 + + + Printing... (page %1) + 인쇄 중... (%1쪽) + + + Printing completed + 인쇄가 완료되었습니다 + + + Printing aborted + 인쇄가 중단되었습니다 + + + Search wrapped. + 검색이 다시 시작되었습니다. + + + Qt Linguist + Qt Linguist + + + Cannot find the string '%1'. + 문자열 '%1'을(를) 찾을 수 없습니다. + + + Search And Translate in '%1' - Qt Linguist + '%1'에서 찾아서 번역하기 - Qt Linguist + + + Translate - Qt Linguist + 번역 - Qt Linguist + + + Translated %n entry(s) + + 항목 %n개를 번역하였습니다 + + + + No more occurrences of '%1'. Start over? + '%1'을(를) 더 이상 찾을 수 없습니다. 처음부터 다시 시작하시겠습니까? + + + Create New Phrase Book + 새 단어장 만들기 + + + Qt phrase books (*.qph) +All files (*) + Qt 단어장 (*.qph) +모든 파일 (*) + + + Phrase book created. + 단어장을 만들었습니다. + + + Open Phrase Book + 단어장 열기 + + + Qt phrase books (*.qph);;All files (*) + Qt 단어장 (*.qph);;모든 파일 (*) + + + %n phrase(s) loaded. + + 단어 %n개를 불러왔습니다. + + + + Add to phrase book + 단어장에 추가 + + + No appropriate phrasebook found. + 사용 가능한 단어장이 없습니다. + + + Adding entry to phrasebook %1 + 단어장 %1에 항목 추가 + + + Select phrase book to add to + 추가할 단어장 선택 + + + Unable to launch Qt Assistant (%1) + Qt Assistant (%1)를 실행할 수 없습니다 + + + Version %1 + 버전 %1 + + + <center><img src=":/images/splash.png"/></img><p>%1</p></center><p>Qt Linguist is a tool for adding translations to Qt applications.</p><p>Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + <center><img src=":/images/splash.png"/></img><p>%1</p></center><p>Qt Linguist는 Qt 프로그램을 번역하는 도구입니다.</p><p>저작권자 (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + + + Do you want to save the modified files? + 수정된 파일을 저장하시겠습니까? + + + Do you want to save '%1'? + '%1'을(를) 저장하시겠습니까? + + + Qt Linguist[*] + Qt Linguist[*] + + + %1[*] - Qt Linguist + %1[*] - Qt Linguist + + + No untranslated translation units left. + 모든 번역 단위가 번역되었습니다. + + + &Window + 창(&W) + + + Minimize + 최소화 + + + Ctrl+M + Ctrl+M + + + Display the manual for %1. + %1의 도움말을 표시합니다. + + + Display information about %1. + %1의 정보를 표시합니다. + + + &Save '%1' + '%1' 저장(&S) + + + Save '%1' &As... + '%1' 다른 이름으로 저장(&A)... + + + Release '%1' + '%1' 배포 + + + Release '%1' As... + '%1' 다른 이름으로 배포... + + + &Close '%1' + '%1' 닫기(&C) + + + &Save + 저장(&S) + + + &Close + 닫기(&C) + + + Save All + 모두 저장 + + + Close All + 모두 닫기 + + + &Release + 배포(&R) + + + Translation File &Settings for '%1'... + '%1'의 번역 파일 설정(&S)... + + + &Batch Translation of '%1'... + '%1' 일괄 번역(&B)... + + + Search And &Translate in '%1'... + '%1'에서 찾아서 번역(&T)... + + + Search And &Translate... + 찾아서 번역(&T)... + + + Cannot read from phrase book '%1'. + 단어장 '%1'에서 읽을 수 없습니다. + + + Close this phrase book. + 이 단어장을 닫습니다. + + + Enables you to add, modify, or delete entries in this phrase book. + 단어장의 항목을 추가, 수정, 삭제할 수 있습니다. + + + Print the entries in this phrase book. + 이 단어장의 항목을 인쇄합니다. + + + Cannot create phrase book '%1'. + 단어장 '%1'을(를) 만들 수 없습니다. + + + Do you want to save phrase book '%1'? + 단어장 '%1'을(를) 저장하시겠습니까? + + + All + 모두 + + + + MessageEditor + + + This is the right panel of the main window. + + + + Russian + 러시아어 + + + German + 독일어 + + + Japanese + 일본어 + + + French + 프랑스어 + + + Polish + 폴란드어 + + + Chinese + 중국어 + + + This whole panel allows you to view and edit the translation of some source text. + 이 패널에서는 원본 텍스트의 번역을 보거나 편집할 수 있습니다. + + + Source text + 원본 텍스트 + + + This area shows the source text. + 이 영역은 원본 텍스트를 표시합니다. + + + Source text (Plural) + 원본 텍스트 (복수형) + + + This area shows the plural form of the source text. + 이 영역은 원본 텍스트의 복수형을 표시합니다. + + + Developer comments + 개발자 주석 + + + This area shows a comment that may guide you, and the context in which the text occurs. + 이 영역은 개발자가 입력한 설명이나 텍스트가 나오는 상황을 알려 줍니다. + + + Here you can enter comments for your own use. They have no effect on the translated applications. + 역자주를 입력할 수 있습니다. 번역된 프로그램에는 나타나지 않습니다. + + + %1 translation (%2) + %1 번역 (%2) + + + This is where you can enter or modify the translation of the above source text. + 원본 텍스트의 번역을 입력하거나 수정할 수 있습니다. + + + %1 translation + %1 번역 + + + %1 translator comments + %1 역자주 + + + '%1' +Line: %2 + '%1' +줄: %2 + + + + MessageModel + + Completion status for %1 + %1의 번역 상태 + + + <file header> + <파일 헤더> + + + <context comment> + <컨텍스트 주석> + + + <unnamed context> + <이름 없는 컨텍스트> + + + + PhraseBook + + Parse error at line %1, column %2 (%3). + %1번째 줄, %2번째 칸에서 처리 오류 발생(%3). + + + + PhraseBookBox + + Edit Phrase Book + 단어장 편집 + + + This window allows you to add, modify, or delete entries in a phrase book. + 단어장의 항목을 추가, 수정, 삭제할 수 있습니다. + + + &Translation: + 번역(&T): + + + This is the phrase in the target language corresponding to the source phrase. + 원문의 대상 언어로 된 번역문입니다. + + + S&ource phrase: + 원문(&O): + + + This is a definition for the source phrase. + 원문의 정의입니다. + + + This is the phrase in the source language. + 원문 텍스트입니다. + + + &Definition: + 정의(&D): + + + Click here to add the phrase to the phrase book. + 단어장에 단어를 추가하려면 누르십시오. + + + &New Entry + 새 항목(&N) + + + Click here to remove the entry from the phrase book. + 단어장에서 항목을 삭제하려면 누르십시오. + + + &Remove Entry + 항목 삭제(&R) + + + Settin&gs... + 설정(&G)... + + + Click here to save the changes made. + 변경 사항을 저장하려면 누르십시오. + + + &Save + 저장(&S) + + + Click here to close this window. + 이 창을 닫으려면 누르십시오. + + + Close + 닫기 + + + + Go to Phrase > Edit Phrase Book... The dialog that pops up is a PhraseBookBox. + + + + (New Entry) + (새 항목) + + + %1[*] - Qt Linguist + %1[*] - Qt Linguist + + + Qt Linguist + Qt Linguist + + + Cannot save phrase book '%1'. + 단어장 '%1'을(를) 저장할 수 없습니다. + + + + PhraseModel + + Source phrase + 원문 + + + Translation + 번역 + + + Definition + 정의 + + + + PhraseView + + Insert + 삽입 + + + Edit + 편집 + + + Guess (%1) + 추측 (%1) + + + Guess + 추측 + + + + QObject + + GNU Gettext localization files + GNU Gettext 번역 파일 + + + GNU Gettext localization template files + GNU Gettext 번역 템플릿 파일 + + + Compiled Qt translations + 컴파일된 Qt 번역 + + + Qt Linguist 'Phrase Book' + Qt Linguist '단어장' + + + Qt translation sources (format 1.1) + Qt 번역 원본 파일 (1.1 형식) + + + Qt translation sources (format 2.0) + Qt 번역 원본 파일 (2.0 형식) + + + Qt translation sources (latest format) + Qt 번역 원본 파일 (최신 형식) + + + XLIFF localization files + XLIFF 번역 파일 + + + lupdate version %1 + + lupdate 버전 %1 + + + + Translation files (%1);; + 번역 파일 (%1);; + + + All files (*) + 모든 파일 (*) + + + Qt Linguist + Qt Linguist + + + + SourceCodeView + + <i>Source code not available</i> + <i>원본 코드를 사용할 수 없음</i> + + + <i>File %1 not available</i> + <i>파일 %1을(를) 사용할 수 없음</i> + + + <i>File %1 not readable</i> + <i>파일 %1에서 읽을 수 없음</i> + + + + Statistics + + Statistics + 통계 + + + Close + 닫기 + + + Translation + 번역 + + + Source + 원문 + + + 0 + 0 + + + Words: + 단어 수: + + + Characters: + 글자 수: + + + Characters (with spaces): + 글자 수(공백 포함): + + + + TranslateDialog + + This window allows you to search for some text in the translation source file. + 번역 원본 파일의 텍스트를 찾을 수 있습니다. + + + Type in the text to search for. + 검색할 텍스트를 입력하십시오. + + + Find &source text: + 찾을 문자열(&S): + + + &Translate to: + 다음으로 번역(&T): + + + Search options + 찾기 옵션 + + + Texts such as 'TeX' and 'tex' are considered as different when checked. + 선택하면 'TeX'와 'tex'를 다른 문자열로 취급합니다. + + + Match &case + 대소문자 구분(&C) + + + Mark new translation as &finished + 새 번역을 완료됨으로 표시(&F) + + + Click here to find the next occurrence of the text you typed in. + 입력한 텍스트가 다음에 등장하는 곳을 찾습니다. + + + Find Next + 다음 찾기 + + + Translate + 번역 + + + Translate All + 모두 번역 + + + Click here to close this window. + 이 창을 닫으려면 누르십시오. + + + Cancel + 취소 + + + + TranslationSettingsDialog + + Source language + 원본 언어 + + + Language + 언어 + + + Country/Region + 국가/지역 + + + Target language + 대상 언어 + + + Settings for '%1' - Qt Linguist + '%1' 설정 - Qt Linguist + + + Any Country + 임의의 국가 + + + diff --git a/translations/qt_help_ko.ts b/translations/qt_help_ko.ts new file mode 100644 index 0000000..4a62287 --- /dev/null +++ b/translations/qt_help_ko.ts @@ -0,0 +1,318 @@ + + + + + QCLuceneResultWidget + + Search Results + 검색 결과 + + + Note: + 메모: + + + The search results may not be complete since the documentation is still being indexed! + 문서의 인덱싱 작업이 진행 중이므로 검색 결과가 완전하지 않을 수도 있습니다! + + + Your search did not match any documents. + 검색 결과가 없습니다. + + + (The reason for this might be that the documentation is still being indexed.) + (문서를 현재 인덱싱 중이므로 결과가 없을 수도 있습니다.) + + + + QHelp + + Untitled + 제목 없음 + + + + QHelpCollectionHandler + + The collection file '%1' is not set up yet! + 모음집 파일 '%1'이(가) 설정되지 않았습니다! + + + Cannot load sqlite database driver! + sqlite 데이터베이스 드라이버를 불러올 수 없습니다! + + + Cannot open collection file: %1 + 모음집 파일을 열 수 없음: %1 + + + Cannot create tables in file %1! + 파일 %1에 테이블을 만들 수 없습니다! + + + The collection file '%1' already exists! + 모음집 파일 '%1'이(가) 이미 존재합니다! + + + Cannot create directory: %1 + 디렉터리를 만들 수 없음: %1 + + + Cannot copy collection file: %1 + 모음집 파일을 복사할 수 없음: %1 + + + Unknown filter '%1'! + 알 수 없는 필터 '%1'! + + + Cannot register filter %1! + 필터 '%1'을(를) 등록할 수 없습니다! + + + Cannot open documentation file %1! + 문서 파일 %1을(를) 열 수 없습니다! + + + Invalid documentation file '%1'! + 문서 파일 '%1'이(가) 잘못되었습니다! + + + The namespace %1 was not registered! + 네임스페이스 %1이(가) 등록되지 않았습니다! + + + Namespace %1 already exists! + 네임스페이스 %1이(가) 이미 존재합니다! + + + Cannot register namespace '%1'! + 네임스페이스 '%1'을(를) 등록할 수 없습니다! + + + Cannot open database '%1' to optimize! + 데이터베이스 '%1'을(를) 최적화하기 위하여 열 수 없습니다! + + + + QHelpDBReader + + Cannot open database '%1' '%2': %3 + The placeholders are: %1 - The name of the database which cannot be opened %2 - The unique id for the connection %3 - The actual error string + 데이터베이스 '%1' '%2'을(를) 열 수 없음: %3 + + + + QHelpEngineCore + + Cannot open documentation file %1: %2! + 문서 파일 %1을(를) 열 수 없음: %2! + + + The specified namespace does not exist! + 지정한 네임스페이스가 존재하지 않습니다! + + + + QHelpGenerator + + Invalid help data! + 도움말 데이터가 잘못되었습니다! + + + No output file name specified! + 출력 파일 이름이 지정되지 않았습니다! + + + The file %1 cannot be overwritten! + 파일 %1에 겹쳐쓸 수 없습니다! + + + Building up file structure... + 파일 구조 생성 중... + + + Cannot open data base file %1! + 데이터베이스 파일 %1을(를) 열 수 없습니다! + + + Cannot register namespace %1! + 네임스페이스 %1을(를) 등록할 수 없습니다! + + + Insert custom filters... + 사용자 정의 필터 추가... + + + Insert help data for filter section (%1 of %2)... + 필터 섹션 (%2 중 %1)에 도움말 데이터 추가... + + + Documentation successfully generated. + 문서가 성공적으로 생성되었습니다. + + + Some tables already exist! + 일부 테이블이 이미 존재합니다! + + + Cannot create tables! + 테이블을 만들 수 없습니다! + + + Cannot register virtual folder! + 가상 폴더를 등록할 수 없습니다! + + + Insert files... + 파일 추가... + + + The referenced file %1 must be inside or within a subdirectory of (%2). Skipping it. + 참조되는 파일 %1은(는) (%2) 그 자체 및 하위 디렉터리에 있어야 합니다. 건너뜁니다. + + + The file %1 does not exist! Skipping it. + 파일 %1이(가) 존재하지 않습니다! 건너뜁니다. + + + Cannot open file %1! Skipping it. + 파일 %1을(를) 열 수 없습니다! 건너뜁니다. + + + The filter %1 is already registered! + 필터 %1이(가) 이미 등록되었습니다! + + + Cannot register filter %1! + 필터 %1을(를) 등록할 수 없습니다! + + + Insert indices... + 인덱스 추가... + + + Insert contents... + 내용 추가... + + + Cannot insert contents! + 내용을 추가할 수 없습니다! + + + Cannot register contents! + 내용을 등록할 수 없습니다! + + + File '%1' does not exist. + 파일 '%1'이(가) 존재하지 않습니다. + + + File '%1' cannot be opened. + 파일 '%1'을(를) 열 수 없습니다. + + + File '%1' contains an invalid link to file '%2' + 파일 '%1'이(가) 파일 '%2'(으)로 가는 올바르지 않은 링크를 포함합니다 + + + Invalid links in HTML files. + HTML 파일에 잘못된 링크가 있습니다. + + + + QHelpProject + + Unknown token. + 알 수 없는 토큰. + + + Unknown token. Expected "QtHelpProject"! + 알 수 없는 토큰. "QtHelpProject"를 예상하였습니다! + + + Error in line %1: %2 + %1줄에 오류가 있음: %2 + + + Virtual folder has invalid syntax. + 가상 폴더 문법이 잘못되었습니다. + + + Namespace has invalid syntax. + 네임스페이스 문법이 잘못되었습니다. + + + Missing namespace in QtHelpProject. + QtHelpProject에 네임스페이스가 없습니다. + + + Missing virtual folder in QtHelpProject + QtHelpProject에 가상 폴더가 없습니다 + + + Missing attribute in keyword at line %1. + %1줄에 있는 키워드에 속성이 없습니다. + + + The input file %1 could not be opened! + 입력 파일 %1을(를) 열 수 없습니다! + + + + QHelpSearchQueryWidget + + Search for: + 찾을 단어: + + + Previous search + 이전 찾기 + + + Next search + 다음 찾기 + + + Search + 찾기 + + + Advanced search + 고급 검색 + + + words <B>similar</B> to: + 다음과 <B>비슷한</B> 단어: + + + <B>without</B> the words: + 다음 단어 <B>제외</B>: + + + with <B>exact phrase</B>: + 다음 <B>정확한 구절</B>: + + + with <B>all</B> of the words: + 다음 단어 <B>모두</B> 포함: + + + with <B>at least one</B> of the words: + 다음 단어 중 <B>최소한 한 단어</B> 포함: + + + + QHelpSearchResultWidget + + %1 - %2 of %n Hits + + 검색 결과 %n개 중 %1 - %2 + + + + 0 - 0 of 0 Hits + 검색 결과 0개 중 0 - 0 + + + diff --git a/translations/qt_ko.ts b/translations/qt_ko.ts new file mode 100644 index 0000000..c7ab8e3 --- /dev/null +++ b/translations/qt_ko.ts @@ -0,0 +1,9941 @@ + + + + + CloseButton + + Close Tab + 탭 닫기 + + + + FakeReply + + Fake error ! + 가짜 오류! + + + Invalid URL + 잘못된 URL + + + + MAC_APPLICATION_MENU + + Services + 서비스 + + + Hide %1 + %1 숨기기 + + + Hide Others + 다른 항목 숨기기 + + + Show All + 모두 보이기 + + + Preferences... + 설정... + + + Quit %1 + %1 끝내기 + + + About %1 + %1 정보 + + + + Phonon:: + + Notifications + 알림 + + + Music + 음악 + + + Video + 비디오 + + + Communication + 대화 + + + Games + 게임 + + + Accessibility + 접근성 + + + + Phonon::AudioOutput + + <html>The audio playback device <b>%1</b> does not work.<br/>Falling back to <b>%2</b>.</html> + <html>오디오 재생 장치 <b>%1</b>을(를) 사용할 수 없습니다.<br />장치 <b>%2</b>(으)로 전환합니다.</html> + + + <html>Switching to the audio playback device <b>%1</b><br/>which just became available and has higher preference.</html> + <html>지금 사용할 수 있게 된 우선 순위가 높은 오디오 장치<br /><b>%1</b>(으)로 전환합니다.</html> + + + Revert back to device '%1' + 장치 '%1'(으)로 전환함 + + + <html>Switching to the audio playback device <b>%1</b><br/>which has higher preference or is specifically configured for this stream.</html> + <html>이 스트림을 위하여 설정하였거나 우선 순위가 더 높은<br />오디오 재생 장치 <b>%1</b>(으)로 전환합니다.</html> + + + + Phonon::Gstreamer::Backend + + Warning: You do not seem to have the package gstreamer0.10-plugins-good installed. + Some video features have been disabled. + 경고: gstreamer0.10-plugins-good 패키지가 없는 것 같습니다. + 일부 비디오 기능을 사용할 수 없습니다. + + + Warning: You do not seem to have the base GStreamer plugins installed. + All audio and video support has been disabled + 경고: GStreamer 기본 플러그인이 없는 것 같습니다. + 모든 오디오 및 비디오 지원을 사용할 수 없습니다 + + + + Phonon::Gstreamer::MediaObject + + Cannot start playback. +Check your GStreamer installation and make sure you +have libgstreamer-plugins-base installed. + 재생을 시작할 수 없습니다. + +Gstreamer 설치 상태를 확인해 보시고 +libgstreamer-plugins-base 패키지의 설치 상태를 확인해 보십시오. + + + Cannot start playback. + +Check your GStreamer installation and make sure you +have libgstreamer-plugins-base installed. + 재생을 시작할 수 없습니다. + +Gstreamer 설치 상태를 확인해 보시고 +libgstreamer-plugins-base 패키지의 설치 상태를 확인해 보십시오. + + + Missing codec helper script assistant. + 코덱 도우미 스크립트가 없습니다. + + + Plugin codec installation failed for codec: %0 + 다음 코덱을 위한 플러그인을 설치할 수 없음: %0 + + + A required codec is missing. You need to install the following codec(s) to play this content: %0 + 필요한 코덱이 없습니다. 이 컨텐츠를 재생하려면 다음 코덱이 필요합니다: %0 + + + Could not open media source. + 미디어 원본을 열 수 없습니다. + + + Invalid source type. + 원본 종류가 잘못되었습니다. + + + Could not locate media source. + 미디어 원본을 찾을 수 없습니다. + + + Could not open audio device. The device is already in use. + 오디오 장치를 열 수 없습니다. 장치가 사용 중입니다. + + + Could not decode media source. + 미디어 원본을 디코딩할 수 없습니다. + + + + Phonon::MMF + + Audio Output + 오디오 출력 + + + The audio output device + 오디오 출력 장치 + + + No error + 오류 없음 + + + Not found + 찾을 수 없음 + + + Out of memory + 메모리 부족 + + + Not supported + 지원하지 않음 + + + Overflow + 넘침 + + + Underflow + Underline context menu item + 비어 있음 + + + Already exists + QSystemSemaphore + 이미 존재함 + + + Underflow + 비어 있음 + + + Already exists + 이미 존재함 + + + Path not found + 경로를 찾을 수 없음 + + + In use + 사용 중 + + + Not ready + 준비되지 않았음 + + + Access denied + 접근이 거부됨 + + + Could not connect + 연결할 수 없음 + + + Disconnected + 연결 끊김 + + + Permission denied + 권한이 거부됨 + + + Insufficient bandwidth + 대역폭 부족 + + + Network unavailable + 네트워크를 사용할 수 없음 + + + Network communication error + 네트워크 통신 오류 + + + Streaming not supported + 스트리밍 지원하지 않음 + + + Server alert + 서버 알림 + + + Invalid protocol + 잘못된 프로토콜 + + + Invalid URL + 잘못된 URL + + + Multicast error + 멀티캐스트 오류 + + + Proxy server error + 프록시 서버 오류 + + + Proxy server not supported + 프록시 서버 지원하지 않음 + + + Audio output error + 오디오 출력 오류 + + + Video output error + 비디오 출력 오류 + + + Decoder error + 디코더 오류 + + + Audio or video components could not be played + 오디오나 비디오 구성 요소를 재생할 수 없음 + + + DRM error + DRM 오류 + + + Unknown error (%1) + 알 수 없는 오류 (%1) + + + + Phonon::MMF::AbstractMediaPlayer + + Not ready to play + 재생이 준비되지 않았음 + + + Error opening file + 파일 열기 오류 + + + Error opening URL + URL 열기 오류 + + + Error opening resource + 자원 열기 오류 + + + Error opening source: resource not opened + 원본을 열 수 없음: 자원이 열리지 않았음 + + + Setting volume failed + 음량 설정 실패 + + + Loading clip failed + 클립 불러오기 실패 + + + Playback complete + 재생 완료됨 + + + Download error + 다운로드 오류 + + + + Phonon::MMF::AbstractVideoPlayer + + Pause failed + 일시 정지 실패 + + + Seek failed + QSystemSemaphore + 검색 실패 + + + Seek failed + 검색 실패 + + + Getting position failed + 위치 가져오기 실패 + + + Opening clip failed + 클립 열기 실패 + + + + Phonon::MMF::AudioEqualizer + + %1 Hz + %1 Hz + + + + Phonon::MMF::AudioPlayer + + Getting position failed + 위치 가져오기 실패 + + + + Phonon::MMF::DsaVideoPlayer + + Video display error + 비디오 표시 오류 + + + + Phonon::MMF::EffectFactory + + Enabled + 사용 가능 + + + + Phonon::MMF::EnvironmentalReverb + + Decay HF ratio (%) + DecayHFRatio: Ratio of high-frequency decay time to the value specified by DecayTime. + 붕괴 HF 비율 (%) + + + Decay time (ms) + DecayTime: Time over which reverberation is diminished. + 붕괴 시간 (ms) + + + Density (%) + Density Delay between first and subsequent reflections. Note that the S60 platform documentation does not make clear the distinction between this value and the Diffusion value. + 밀도 (%) + + + Diffusion (%) + Diffusion: Delay between first and subsequent reflections. Note that the S60 platform documentation does not make clear the distinction between this value and the Density value. + 혼합 (%) + + + Reflections delay (ms) + ReflectionsDelay: Amount of delay between the arrival the direct path from the source and the arrival of the first reflection. + 반사 지연 시간 (ms) + + + Reflections level (mB) + ReflectionsLevel: Amplitude of reflections. This value is corrected by the RoomLevel to give the final reflection amplitude. + 반사 레벨 (mB) + + + Reverb delay (ms) + ReverbDelay: Amount of time between arrival of the first reflection and start of the late reverberation. + 리버브 지연 시간 (ms) + + + Reverb level (mB) + ReverbLevel Amplitude of reverberations. This value is corrected by the RoomLevel to give the final reverberation amplitude. + 리버브 레벨 (mB) + + + Room HF level + RoomHFLevel: Amplitude of low-pass filter used to attenuate the high frequency component of reflected sound. + 룸 HF 레벨 + + + Room level (mB) + RoomLevel: Master volume control for all reflected sound. + 룸 레벨 (mB) + + + + Phonon::MMF::MediaObject + + Error opening source: type not supported + 원본 열기 오류: 형식을 지원하지 않음 + + + Error opening source: resource is compressed + 원본 열기 오류: 자원이 압축되어 있음 + + + Error opening source: resource not valid + 원본 열기 오류: 자원이 올바르지 않음 + + + Error opening source: media type could not be determined + 원본 열기 오류: 미디어 형식을 결정할 수 없음 + + + + Phonon::MMF::StereoWidening + + Level (%) + 레벨 (%) + + + + Phonon::MMF::SurfaceVideoPlayer + + Video display error + 비디오 표시 오류 + + + + Phonon::VolumeSlider + + Volume: %1% + 음량: %1% + + + Use this slider to adjust the volume. The leftmost position is 0%, the rightmost is %1% + 이 슬라이더를 사용하여 음량을 조정하십시오. 맨 왼쪽은 0%, 맨 오른쪽은 %1%입니다 + + + Muted + 음소거 + + + + Q3Accel + + %1, %2 not defined + %1, %2이(가) 정의되지 않았습니다 + + + Ambiguous %1 not handled + 모호한 %1이(가) 처리되지 않았습니다 + + + + Q3DataTable + + True + + + + False + 거짓 + + + Insert + 삽입 + + + Update + 업데이트 + + + Delete + 삭제 + + + + Q3FileDialog + + Copy or Move a File + 파일 복사 또는 이동 + + + Read: %1 + 읽기: %1 + + + Write: %1 + 쓰기: %1 + + + Cancel + 취소 + + + All Files (*) + 모든 파일 (*) + + + Name + 이름 + + + Size + 크기 + + + Type + 형식 + + + Date + 날짜 + + + Attributes + 속성 + + + &OK + 확인(&O) + + + Look &in: + 다음에서 찾기(&I): + + + File &name: + 파일 이름(&N): + + + File &type: + 파일 형식(&T): + + + Back + 뒤로 + + + One directory up + 한 단계 위로 + + + Create New Folder + 새 폴더 만들기 + + + List View + 목록으로 보기 + + + Detail View + 자세히 보기 + + + Preview File Info + 파일 정보 미리 보기 + + + Preview File Contents + 파일 내용 미리 보기 + + + Read-write + 읽기-쓰기 + + + Read-only + 읽기 전용 + + + Write-only + 쓰기 전용 + + + Inaccessible + 접근할 수 없음 + + + Symlink to File + 파일로 향한 심볼릭 링크 + + + Symlink to Directory + 디렉터리로 향한 심볼릭 링크 + + + Symlink to Special + 특수 파일로 향한 심볼릭 링크 + + + File + 파일 + + + Dir + 디렉터리 + + + Special + 특수 파일 + + + Open + 열기 + + + Save As + 다른 이름으로 저장 + + + &Open + 열기(&O) + + + &Save + 저장(&S) + + + &Rename + 이름 바꾸기(&R) + + + &Delete + 삭제(&D) + + + R&eload + 새로 고침(&E) + + + Sort by &Name + 이름으로 정렬(&N) + + + Sort by &Size + 크기로 정렬(&S) + + + Sort by &Date + 날짜로 정렬(&D) + + + &Unsorted + 정렬하지 않음(&U) + + + Sort + 정렬 + + + Show &hidden files + 숨김 파일 보이기(&H) + + + the file + 파일 + + + the directory + 디렉터리 + + + the symlink + 심볼릭 링크 + + + Delete %1 + %1 삭제 + + + <qt>Are you sure you wish to delete %1 "%2"?</qt> + <qt>%1 "%2"을(를) 삭제하시겠습니까?</qt> + + + &Yes + 예(&Y) + + + &No + 아니오(&N) + + + New Folder 1 + 새 폴더 1 + + + New Folder + 새 폴더 + + + New Folder %1 + 새 폴더 %1 + + + Find Directory + 디렉터리 찾기 + + + Directories + 디렉터리 + + + Directory: + 디렉터리: + + + Error + 오류 + + + %1 +File not found. +Check path and filename. + %1 +파일을 찾을 수 없습니다. +경로와 파일 이름을 확인하십시오. + + + All Files (*.*) + 모든 파일 (*.*) + + + Open + 열기 + + + Select a Directory + 디렉터리 선택 + + + + Q3LocalFs + + Could not read directory +%1 + 다음 디렉터리를 읽을 수 없음 +%1 + + + Could not create directory +%1 + 다음 디렉터리를 만들 수 없음 +%1 + + + Could not remove file or directory +%1 + 파일이나 디렉터리를 삭제할 수 없음 +%1 + + + Could not rename +%1 +to +%2 + %1 +의 이름을 +%2 +(으)로 바꿀 수 없음 + + + Could not open +%1 + 다음을 열 수 없음 +%1 + + + Could not write +%1 + 다음에 쓸 수 없음 +%1 + + + + Q3MainWindow + + Line up + 정렬하기 + + + Customize... + 사용자 정의... + + + + Q3NetworkProtocol + + Operation stopped by the user + 사용자가 동작을 중지함 + + + + Q3ProgressDialog + + Cancel + 취소 + + + + Q3TabDialog + + OK + 확인 + + + Apply + 적용 + + + Help + 도움말 + + + Defaults + 기본값 복원 + + + Cancel + 취소 + + + + Q3TextEdit + + &Undo + 실행 취소(&U) + + + &Redo + 다시 실행(&R) + + + Cu&t + 잘라내기(&T) + + + &Copy + 복사(&C) + + + &Paste + 붙여넣기(&P) + + + Clear + 지우기 + + + Select All + 모두 선택 + + + + Q3TitleBar + + System + 시스템 + + + Restore up + 복원 + + + Minimize + 최소화 + + + Restore down + 복원 + + + Maximize + 최대화 + + + Close + 닫기 + + + Contains commands to manipulate the window + 창을 조작하는 명령을 포함합니다 + + + Puts a minimized window back to normal + 최소화된 창을 되돌립니다 + + + Moves the window out of the way + 창을 숨깁니다 + + + Puts a maximized window back to normal + 최대화된 창을 되돌립니다 + + + Makes the window full screen + 창을 전체 화면으로 만듭니다 + + + Closes the window + 창을 닫습니다 + + + Displays the name of the window and contains controls to manipulate it + 창의 이름을 보여주고 조작하기 위한 컨트롤을 포함합니다 + + + + Q3ToolBar + + More... + 더 보기... + + + + Q3UrlOperator + + The protocol `%1' is not supported + 프로토콜 `%1'은(는) 지원하지 않습니다 + + + The protocol `%1' does not support listing directories + 프로토콜 `%1'에서 디렉터리 목록을 볼 수 없습니다 + + + The protocol `%1' does not support creating new directories + 프로토콜 `%1'에서 새 디렉터리를 만들 수 없습니다 + + + The protocol `%1' does not support removing files or directories + 프로토콜 `%1'에서 파일이나 디렉터리를 삭제할 수 없습니다 + + + The protocol `%1' does not support renaming files or directories + 프로토콜 `%1'에서 파일이나 디렉터리의 이름을 바꿀 수 없습니다 + + + The protocol `%1' does not support getting files + 프로토콜 `%1'에서 파일을 가져올 수 없습니다 + + + The protocol `%1' does not support putting files + 프로토콜 `%1'에서 파일을 올릴 수 없습니다 + + + The protocol `%1' does not support copying or moving files or directories + 프로토콜 `%1'에서 파일이나 디렉터리를 복사하거나 이동할 수 없습니다 + + + (unknown) + (알 수 없음) + + + + Q3Wizard + + &Cancel + 취소(&C) + + + < &Back + < 이전(&B) + + + &Next > + 다음 (&N) > + + + &Finish + 완료(&F) + + + &Help + 도움말(&H) + + + + QAbstractSocket + + Socket operation timed out + 소켓 작업 시간 초과 + + + Operation on socket is not supported + 소켓 작업이 지원되지 않음 + + + Host not found + 호스트를 찾을 수 없음 + + + Connection refused + 연결이 거부됨 + + + Connection timed out + 연결 시간 초과됨 + + + Socket is not connected + 소켓이 연결되지 않음 + + + Network unreachable + 네트워크에 접근할 수 없음 + + + + QAbstractSpinBox + + &Select All + 모두 선택(&S) + + + &Step up + 한 단계 위로(&S) + + + Step &down + 한 단계 아래로(&D) + + + + QAccessibleButton + + Press + 누름 + + + + QApplication + + Activate + 활성화 + + + Activates the program's main window + 프로그램의 주 창 활성화 + + + Executable '%1' requires Qt %2, found Qt %3. + 실행 파일 '%1'은(는) Qt %2을(를) 필요로 하지만 현재 Qt %3이(가) 설치되어 있습니다. + + + Incompatible Qt Library Error + Qt 라이브러리 호환성 오류 + + + QT_LAYOUT_DIRECTION + Translate this string to the string 'LTR' in left-to-right languages or to 'RTL' in right-to-left languages (such as Hebrew and Arabic) to get proper widget layout. + LTR + + + + QAxSelect + + Select ActiveX Control + ActiveX 컨트롤 선택 + + + OK + 확인 + + + &Cancel + 취소(&C) + + + COM &Object: + COM 객체(&O): + + + + QCheckBox + + Uncheck + 선택 해제 + + + Check + 선택 + + + Toggle + 선택 반전 + + + + QColorDialog + + Hu&e: + 색상(&E): + + + &Sat: + 채도(&S): + + + &Val: + 휘도(&V): + + + &Red: + 빨강(&R): + + + &Green: + 녹색(&G): + + + Bl&ue: + 파랑(&U): + + + A&lpha channel: + 투명도(&L): + + + Select Color + 색 선택 + + + &Basic colors + 기본 색상(&B) + + + &Custom colors + 사용자 정의 색상(&C) + + + &Add to Custom Colors + 사용자 정의 색상에 추가(&A) + + + + QComboBox + + False + 거짓 + + + True + + + + Open + 열기 + + + Close + 닫기 + + + + QCoreApplication + + %1: already exists + QSystemSemaphore + %1: 이미 존재함 + + + %1: does not exist + QSystemSemaphore + %1: 존재하지 않음 + + + %1: out of resources + QSystemSemaphore + %1: 자원 부족 + + + %1: unknown error %2 + QSystemSemaphore + %1: 알 수 없는 오류 %2 + + + %1: key is empty + QSystemSemaphore + %1: 키가 없음 + + + %1: unable to make key + QSystemSemaphore + %1: 키를 만들 수 없음 + + + %1: ftok failed + QSystemSemaphore + %1: ftok 실패 + + + + QDB2Driver + + Unable to connect + 연결할 수 없음 + + + Unable to commit transaction + 트랜잭션을 커밋할 수 없음 + + + Unable to rollback transaction + 트랜잭션을 되돌릴 수 없음 + + + Unable to set autocommit + 자동 커밋을 설정할 수 없음 + + + + QDB2Result + + Unable to execute statement + 구문을 실행할 수 없음 + + + Unable to prepare statement + 구문을 준비할 수 없음 + + + Unable to bind variable + 변수를 바인딩할 수 없음 + + + Unable to fetch record %1 + 레코드 %1을(를) 가져올 수 없음 + + + Unable to fetch next + 다음 항목을 가져올 수 없음 + + + Unable to fetch first + 이전 항목을 가져올 수 없음 + + + + QDateTimeEdit + + AM + 오전 + + + am + 오전 + + + PM + 오후 + + + pm + 오후 + + + + QDeclarativeAbstractAnimation + + Cannot animate non-existent property "%1" + 존재하지 않는 속성 "%1"에 애니메이션을 설정할 수 없음 + + + Cannot animate read-only property "%1" + 읽기 전용 속성 "%1"에 애니메이션을 설정할 수 없음 + + + Animation is an abstract class + 애니메이션이 추상 클래스임 + + + + QDeclarativeAnchorAnimation + + Cannot set a duration of < 0 + 0보다 작은 지속 시간을 설정할 수 없음 + + + + QDeclarativeAnchors + + Possible anchor loop detected on fill. + fill에서 앵커 반복 감지됨. + + + Possible anchor loop detected on centerIn. + centerIn에서 앵커 반복 감지됨. + + + Cannot anchor to an item that isn't a parent or sibling. + 부모나 자식이 아닌 항목에 앵커를 설정할 수 없음. + + + Possible anchor loop detected on vertical anchor. + 수직 앵커에서 앵커 반복 감지됨. + + + Possible anchor loop detected on horizontal anchor. + 수평 앵커에서 앵커 반복 감지됨. + + + Cannot specify left, right, and hcenter anchors. + left, right, hcenter 앵커를 지정할 수 없음. + + + Cannot anchor to a null item. + 빈 항목에 앵커를 설정할 수 없음. + + + Cannot anchor a horizontal edge to a vertical edge. + 수평선을 수직선에 앵커로 설정할 수 없음. + + + Cannot anchor item to self. + 자기 자신에 앵커를 설정할 수 없음. + + + Cannot specify top, bottom, and vcenter anchors. + top, bottom, vcenter 앵커를 설정할 수 없음. + + + Baseline anchor cannot be used in conjunction with top, bottom, or vcenter anchors. + 베이스라인 앵커를 top, bottom, vcenter 앵커와 같이 사용할 수 없음. + + + Cannot anchor a vertical edge to a horizontal edge. + 수직선을 수평선에 앵커로 설정할 수 없음. + + + + QDeclarativeAnimatedImage + + Qt was built without support for QMovie + Qt 빌드에 QMovie 지원이 빠졌음 + + + + QDeclarativeBehavior + + Cannot change the animation assigned to a Behavior. + Behavior에 할당된 애니메이션을 변경할 수 없음. + + + + QDeclarativeBinding + + Binding loop detected for property "%1" + 속성 "%1"에서 바인딩 반복이 감지됨 + + + + QDeclarativeCompiledBindings + + Binding loop detected for property "%1" + 속성 "%1"에서 바인딩 반복이 감지됨 + + + + QDeclarativeCompiler + + Invalid property assignment: "%1" is a read-only property + 잘못된 속성 대입: "%1"은(는) 읽기 전용 속성 + + + Invalid property assignment: unknown enumeration + 잘못된 속성 대입: 알 수 없는 열거형 + + + Invalid property assignment: string expected + 잘못된 속성 대입: 문자열이 필요함 + + + Invalid property assignment: url expected + 잘못된 속성 대입: url이 필요함 + + + Invalid property assignment: unsigned int expected + 잘못된 속성 대입: 부호 없는 int가 필요함 + + + Invalid property assignment: int expected + 잘못된 속성 대입: int가 필요함 + + + Invalid property assignment: number expected + 잘못된 속성 대입: 숫자가 필요함 + + + Invalid property assignment: color expected + 잘못된 속성 대입: 색상이 필요함 + + + Invalid property assignment: date expected + 잘못된 속성 대입: 날짜가 필요함 + + + Invalid property assignment: time expected + 잘못된 속성 대입: 시간이 필요함 + + + Invalid property assignment: datetime expected + 잘못된 속성 대입: 날짜와 시간이 필요함 + + + Invalid property assignment: point expected + 잘못된 속성 대입: 점이 필요함 + + + Invalid property assignment: size expected + 잘못된 속성 대입: 크기가 필요함 + + + Invalid property assignment: rect expected + 잘못된 속성 대입: 사각형이 필요함 + + + Invalid property assignment: boolean expected + 잘못된 속성 대입: 참/거짓이 필요함 + + + Invalid property assignment: 3D vector expected + 잘못된 속성 대입: 3차원 벡터가 필요함 + + + Invalid property assignment: unsupported type "%1" + 잘못된 속성 대입: 지원하지 않는 형식 "%1" + + + Element is not creatable. + 원소를 만들 수 없습니다. + + + Component elements may not contain properties other than id + Component 원소는 id 이외의 다른 속성을 포함할 수 없음 + + + Invalid component id specification + 잘못된 컴포넌트 id 지정 + + + id is not unique + 중복되는 id가 있음 + + + Invalid component body specification + 잘못된 컴포넌트 body 지정 + + + Component objects cannot declare new properties. + 컴포넌트 개체에서는 새로운 속성을 정의할 수 없습니다. + + + Component objects cannot declare new signals. + 컴포넌트 개체에서는 새로운 시그널을 정의할 수 없습니다. + + + Component objects cannot declare new functions. + 컴포넌트 개체에서는 새로운 함수를 정의할 수 없습니다. + + + Cannot create empty component specification + 비어 있는 컴포넌트 정의를 만들 수 없음 + + + Incorrectly specified signal assignment + 잘못 지정된 시그널 할당 + + + Cannot assign a value to a signal (expecting a script to be run) + 값을 시그널에 지정할 수 없음 (스크립트가 실행될 것을 예상함) + + + Empty signal assignment + 빈 시그널 할당 + + + Empty property assignment + 빈 속성 할당 + + + Attached properties cannot be used here + 첨부된 속성을 사용할 수 없음 + + + Non-existent attached object + 존재하지 않는 첨부된 개체 + + + Invalid attached object assignment + 잘못된 첨부된 개체 할당 + + + Cannot assign to non-existent default property + 존재하지 않는 기본 속성에 할당할 수 없음 + + + Cannot assign to non-existent property "%1" + 존재하지 않는 속성 "%1"에 할당할 수 없음 + + + Invalid use of namespace + 잘못된 네임스페이스 사용 + + + Not an attached property name + 첨부된 속성 이름이 아님 + + + Invalid use of id property + id 속성을 잘못 사용함 + + + Property has already been assigned a value + 속성에 이미 값이 할당됨 + + + Invalid grouped property access + 잘못된 그룹 속성 접근 + + + Cannot assign a value directly to a grouped property + 그룹 속성에 값을 직접 할당할 수 없음 + + + Invalid property use + 속성을 잘못 사용함 + + + Property assignment expected + 속성 할당이 필요함 + + + Single property assignment expected + 단일 속성 할당이 필요함 + + + Unexpected object assignment + 예상하지 못한 개체 할당 + + + Cannot assign object to list + 개체를 목록에 대입할 수 없음 + + + Can only assign one binding to lists + 목록에는 한 바인딩만 할당할 수 있음 + + + Cannot assign primitives to lists + 원시 타입을 목록에 할당할 수 없음 + + + Cannot assign multiple values to a script property + 스크립트 속성에 다중 값을 할당할 수 없음 + + + Invalid property assignment: script expected + 잘못된 속성 대입: script가 필요함 + + + Cannot assign multiple values to a singular property + 단일 속성에 여러 값을 할당할 수 없음 + + + Cannot assign object to property + 개체를 속성에 할당할 수 없음 + + + "%1" cannot operate on "%2" + "%1"은(는) "%2"에서 작동할 수 없음 + + + Duplicate default property + 중복된 기본 속성 + + + Duplicate property name + 중복된 속성 이름 + + + Property names cannot begin with an upper case letter + 속성 이름은 대문자로 시작할 수 없음 + + + Illegal property name + 잘못된 속성 이름 + + + Duplicate signal name + 중복된 시그널 이름 + + + Signal names cannot begin with an upper case letter + 시그널 이름은 대문자로 시작할 수 없음 + + + Illegal signal name + 잘못된 시그널 이름 + + + Duplicate method name + 중복된 메서드 이름 + + + Method names cannot begin with an upper case letter + 메서드 이름은 대문자로 시작할 수 없음 + + + Illegal method name + 잘못된 메서드 이름 + + + Property value set multiple times + 속성 값이 여러 번 설정됨 + + + Invalid property nesting + 잘못된 속성 중첩 + + + Cannot override FINAL property + FINAL 속성을 재정의할 수 없음 + + + Invalid property type + 잘못된 속성 형식 + + + Invalid empty ID + 잘못된 빈 ID + + + IDs cannot start with an uppercase letter + ID는 대문자로 시작할 수 없음 + + + IDs must start with a letter or underscore + ID는 글자나 밑줄로 시작해야 함 + + + IDs must contain only letters, numbers, and underscores + ID는 글자, 숫자, 밑줄만 포함해야 함 + + + ID illegally masks global JavaScript property + ID가 전역 자바스크립트 속성을 가림 + + + No property alias location + 속성 별명 위치가 지정되지 않음 + + + Invalid alias location + 잘못된 별명 위치 + + + Invalid alias reference. An alias reference must be specified as <id>, <id>.<property> or <id>.<value property>.<property> + 잘못된 별명 참조. 별명 참조는 <id>, <id>.<property> 또는 <id>.<value property>.<property>여야 함 + + + Invalid alias reference. Unable to find id "%1" + 잘못된 별명 참조. id "%1"을(를) 찾을 수 없음 + + + Alias property exceeds alias bounds + 별명 속성이 경계를 벗어남 + + + + QDeclarativeComponent + + Invalid empty URL + 잘못된 빈 URL + + + + QDeclarativeConnections + + Cannot assign to non-existent property "%1" + 존재하지 않는 속성 "%1"에 할당할 수 없음 + + + Connections: nested objects not allowed + 연결: 중첩된 개체를 사용할 수 없음 + + + Connections: syntax error + 연결: 문법 오류 + + + Connections: script expected + 연결: 스크립트가 필요함 + + + + QDeclarativeEngine + + executeSql called outside transaction() + transaction() 밖에서 executeSql이 호출됨 + + + Read-only Transaction + 읽기 전용 트랜잭션 + + + Version mismatch: expected %1, found %2 + 버전 불일치: 사용 중인 버전 %2, 필요한 버전 %1 + + + SQL transaction failed + SQL 트랜잭션 실패 + + + transaction: missing callback + 트랜잭션: 콜백이 없음 + + + SQL: database version mismatch + SQL: 데이터베이스 버전 불일치 + + + + QDeclarativeFlipable + + front is a write-once property + front는 한 번만 쓸 수 있는 속성임 + + + back is a write-once property + back은 한 번만 쓸 수 있는 속성임 + + + + QDeclarativeImportDatabase + + cannot load module "%1": File name case mismatch for "%2" + 모듈 "%1"을(를) 불러올 수 없음: "%2"와(과) 파일 이름 대소문자가 일치하지 않음 + + + module "%1" definition "%2" not readable + 모듈 "%1"의 정의 "%2"을(를) 읽을 수 없음 + + + plugin cannot be loaded for module "%1": %2 + 모듈 "%1"의 플러그인을 불러올 수 없음: %2 + + + module "%1" plugin "%2" not found + 모듈 "%1"의 플러그인 "%2"을(를) 찾을 수 없음 + + + module "%1" version %2.%3 is not installed + 모듈 "%1"의 버전 %2.%3이(가) 설치되지 않았음 + + + module "%1" is not installed + 모듈 "%1"이(가) 설치되지 않았음 + + + "%1": no such directory + "%1": 그러한 디렉터리가 없음 + + + import "%1" has no qmldir and no namespace + import "%1"에 qmldir과 네임스페이스가 없음 + + + - %1 is not a namespace + - %1이(가) 네임스페이스가 아님 + + + - nested namespaces not allowed + - 중첩된 네임스페이스를 사용할 수 없음 + + + local directory + 로컬 디렉터리 + + + is ambiguous. Found in %1 and in %2 + 이(가) 모호합니다. %1와(과) %2에서 찾았습니다 + + + is ambiguous. Found in %1 in version %2.%3 and %4.%5 + 이(가) 모호합니다. %1에서 버전 %2.%3, %4.%5을(를) 찾았습니다 + + + is instantiated recursively + 이(가) 재귀적으로 인스턴스화되었습니다 + + + is not a type + 이(가) 형식이 아닙니다 + + + File name case mismatch for "%2" + 파일 이름의 대소문자가 "%2"와(과) 일치하지 않습니다 + + + + QDeclarativeKeyNavigationAttached + + KeyNavigation is only available via attached properties + KeyNavigation은 연결된 속성에만 사용할 수 있음 + + + + QDeclarativeKeysAttached + + Keys is only available via attached properties + Keys는 연결된 속성에만 사용할 수 있음 + + + + QDeclarativeListModel + + remove: index %1 out of range + remove: 인덱스 %1이(가) 범위를 벗어남 + + + insert: value is not an object + insert: 값이 개체가 아님 + + + insert: index %1 out of range + insert: 인덱스 %1이(가) 범위를 벗어남 + + + move: out of range + move: 범위를 벗어남 + + + append: value is not an object + append: 값이 개체가 아님 + + + set: value is not an object + set: 값이 개체가 아님 + + + set: index %1 out of range + set: 인덱스 %1이(가) 범위를 벗어남 + + + ListElement: cannot contain nested elements + ListElement: 중첩된 원소를 포함할 수 없음 + + + ListElement: cannot use reserved "id" property + ListElement: 예약된 "id" 속성을 사용할 수 없음 + + + ListElement: cannot use script for property value + ListElement: 속성 값으로 스크립트를 사용할 수 없음 + + + ListModel: undefined property '%1' + ListModel: 정의되지 않은 속성 '%1' + + + + QDeclarativeLoader + + Loader does not support loading non-visual elements. + 로더에서 비 시각적 구성 요소를 불러올 수 없습니다. + + + + QDeclarativeParentAnimation + + Unable to preserve appearance under complex transform + 복합 변형 이후 모양을 보존할 수 없음 + + + Unable to preserve appearance under non-uniform scale + 불균일 크기 조정 이후 모양을 보존할 수 없음 + + + Unable to preserve appearance under scale of 0 + 0 이하로 크기를 조정했을 때 모양을 보존할 수 없음 + + + + QDeclarativeParentChange + + Unable to preserve appearance under complex transform + 복합 변형 이후 모양을 보존할 수 없음 + + + Unable to preserve appearance under non-uniform scale + 불균일 크기 조정 이후 모양을 보존할 수 없음 + + + Unable to preserve appearance under scale of 0 + 0 이하로 크기를 조정했을 때 모양을 보존할 수 없음 + + + + QDeclarativeParser + + Illegal unicode escape sequence + 잘못된 유니코드 탈출 시퀀스 + + + Illegal character + 잘못된 글자 + + + Unclosed string at end of line + 줄 끝에서 닫히지 않은 문자열 + + + Illegal escape squence + 잘못된 탈출 시퀀스 + + + Unclosed comment at end of file + 줄 끝에서 닫히지 않은 주석 + + + Illegal syntax for exponential number + 잘못된 지수 문법 + + + Identifier cannot start with numeric literal + 식별자는 숫자로 시작할 수 없음 + + + Unterminated regular expression literal + 끝나지 않은 정규 표현식 리터럴 + + + Invalid regular expression flag '%0' + 잘못된 정규 표현식 플래그 '%0' + + + Unterminated regular expression backslash sequence + 종료되지 않은 정규 표현식 백슬래시 시퀀스 + + + Unterminated regular expression class + 종료되지 않은 정규 표현식 클래스 + + + Syntax error + 구문 오류 + + + Unexpected token `%1' + 예상하지 못한 토큰 '%1' + + + Expected token `%1' + 토큰 '%1'이(가) 필요함 + + + Property value set multiple times + 속성 값이 여러 번 설정됨 + + + Expected type name + 형식 이름이 필요함 + + + Invalid import qualifier ID + 잘못된 가져오기 식별자 ID + + + Reserved name "Qt" cannot be used as an qualifier + 예약됨 이름 "Qt"는 지정자 이름으로 사용할 수 없음 + + + Script import qualifiers must be unique. + 스크립트 가져오기 지정자는 고유해야 합니다. + + + Script import requires a qualifier + 스크립트를 가져오려면 지정자가 필요함 + + + Library import requires a version + 라이브러리를 가져오려면 버전이 필요함 + + + Expected parameter type + 인자 type이 필요함 + + + Invalid property type modifier + 잘못된 속성 type 수정자 + + + Unexpected property type modifier + 예상하지 못한 속성 type 수정자 + + + Expected property type + 속성 type이 필요함 + + + Readonly not yet supported + 읽기 전용이 지원되지 않음 + + + JavaScript declaration outside Script element + Script 원소 밖에서 자바스크립트가 선언됨 + + + + QDeclarativePauseAnimation + + Cannot set a duration of < 0 + 0보다 작은 지속 시간을 설정할 수 없음 + + + + QDeclarativePixmap + + Error decoding: %1: %2 + %1 디코딩 중 오류 발생: %2 + + + Failed to get image from provider: %1 + 공급자에서 그림을 가져올 수 없음: %1 + + + Cannot open: %1 + 다음을 열 수 없음: %1 + + + + QDeclarativePropertyAnimation + + Cannot set a duration of < 0 + 0보다 작은 지속 시간을 설정할 수 없음 + + + + QDeclarativePropertyChanges + + PropertyChanges does not support creating state-specific objects. + PropertyChanges는 상태별 개체를 만들 수 없습니다. + + + Cannot assign to non-existent property "%1" + 존재하지 않는 속성 "%1"에 할당할 수 없음 + + + Cannot assign to read-only property "%1" + 읽기 전용 속성 "%1"에 할당할 수 없음 + + + + QDeclarativeTextInput + + Could not load cursor delegate + 커서 선언을 불러올 수 없음 + + + Could not instantiate cursor delegate + 커서 선언을 인스턴스화할 수 없음 + + + + QDeclarativeTypeLoader + + Script %1 unavailable + 스크립트 %1을(를) 사용할 수 없음 + + + Type %1 unavailable + 형식 %1을(를) 사용할 수 없음 + + + Namespace %1 cannot be used as a type + 네임스페이스 %1을(를) 형식으로 사용할 수 없음 + + + %1 %2 + %1 %2 + + + + QDeclarativeVME + + Unable to create object of type %1 + 형식 %1인 개체를 만들 수 없음 + + + Cannot assign value %1 to property %2 + 속성 %2에 값 %1을(를) 할당할 수 없음 + + + Cannot assign object type %1 with no default method + 개체 타입 %1에 기본 메서드를 지정하지 않고 할당할 수 없음 + + + Cannot connect mismatched signal/slot %1 %vs. %2 + 일치하지 않는 시그널/슬롯 %1 %vs %2을(를) 연결할 수 없음 + + + Cannot assign an object to signal property %1 + 개체를 시그널 속성 %1에 할당할 수 없음 + + + Cannot assign object to list + 개체를 목록에 할당할 수 없음 + + + Cannot assign object to interface property + 개체를 인터페이스 속성에 할당할 수 없음 + + + Unable to create attached object + 첨부된 개체를 만들 수 없음 + + + Cannot set properties on %1 as it is null + %1이(가) null이므로 속성을 설정할 수 없음 + + + + QDeclarativeVisualDataModel + + Delegate component must be Item type. + 하위 구성 요소는 Item 형식이어야 합니다. + + + + QDeclarativeXmlListModel + + Qt was built without support for xmlpatterns + Qt 빌드에 xmlpatterns 지원이 빠졌음 + + + + QDeclarativeXmlListModelRole + + An XmlRole query must not start with '/' + XmlRole 쿼리는 '/'로 시작하면 안 됨 + + + + QDeclarativeXmlRoleList + + An XmlListModel query must start with '/' or "//" + XmlListModel 쿼리는 '/'나 '//'로 시작해야 함 + + + + QDial + + QDial + QDial + + + SpeedoMeter + 속도계 + + + SliderHandle + 슬라이더 핸들 + + + + QDialog + + Done + 완료 + + + What's This? + 이것에 대한 설명 + + + + QDialogButtonBox + + OK + 확인 + + + &OK + 확인(&O) + + + &Save + 저장(&S) + + + Save + 저장 + + + Open + 열기 + + + &Cancel + 취소(&C) + + + Cancel + 취소 + + + &Close + 닫기(&C) + + + Close + 닫기 + + + Apply + 적용 + + + Reset + 초기화 + + + Help + 도움말 + + + Don't Save + 저장하지 않음 + + + Close without Saving + 저장하지 않고 닫기 + + + Discard + 무시 + + + &Yes + 예(&Y) + + + Yes to &All + 모두 예(&A) + + + &No + 아니오(&N) + + + N&o to All + 모두 아니오(&O) + + + Save All + 모두 저장 + + + Abort + 중단 + + + Retry + 다시 시도 + + + Ignore + 무시 + + + Restore Defaults + 기본값 복원 + + + + QDirModel + + Name + 이름 + + + Size + 크기 + + + Kind + Match OS X Finder + 형식 + + + Type + All other platforms + 형식 + + + Date Modified + 수정한 날짜 + + + + QDockWidget + + Close + 닫기 + + + Dock + 붙이기 + + + Float + 띄우기 + + + + QDoubleSpinBox + + More + 더 보기 + + + Less + 덜 보기 + + + + QErrorMessage + + Debug Message: + 디버그 메시지: + + + Warning: + 경고: + + + Fatal Error: + 치명적 오류: + + + &Show this message again + 이 메시지를 다시 보이기(&S) + + + &OK + 확인(&O) + + + + QFile + + Destination file exists + 대상 파일이 존재함 + + + Will not rename sequential file using block copy + 블록 복사를 사용하여 연속적인 파일 이름을 바꾸지 않음 + + + Cannot remove source file + 원본 파일을 삭제할 수 없음 + + + Cannot open %1 for input + %1에서 입력을 받기 위하여 열 수 없음 + + + Cannot open for output + 출력을 위하여 열 수 없음 + + + Failure to write block + 블록을 쓸 수 없음 + + + Cannot create %1 for output + %1에 쓰기 위하여 열 수 없음 + + + + QFileDialog + + Look in: + 다음에서 찾기: + + + Back + 뒤로 + + + Go back + 뒤로 가기 + + + Forward + 앞으로 + + + Go forward + Forward context menu item + 앞으로 가기 + + + Parent Directory + 부모 디렉터리 + + + Go to the parent directory + 부모 디렉터리로 가기 + + + Create New Folder + 새 폴더 만들기 + + + Create a New Folder + 새 폴더 만들기 + + + List View + 목록으로 보기 + + + Change to list view mode + 목록 보기 모드로 전환 + + + Detail View + 자세히 보기 + + + Change to detail view mode + 자세히 보기 모드로 전환 + + + Files of type: + 파일 형식: + + + Find Directory + 디렉터리 찾기 + + + Open + 열기 + + + Save As + 다른 이름으로 저장 + + + All Files (*) + 모든 파일 (*) + + + Show + 보이기 + + + &Rename + 이름 바꾸기(&R) + + + &Delete + 삭제(&D) + + + Show &hidden files + 숨김 파일 보이기(&H) + + + &New Folder + 새 폴더(&N) + + + Directory: + 디렉터리: + + + File &name: + 파일 이름(&N): + + + &Open + 열기(&O) + + + &Save + 저장(&S) + + + Directories + 디렉터리 + + + &Choose + 선택(&C) + + + %1 +Directory not found. +Please verify the correct directory name was given. + %1 +디렉터리를 찾을 수 없습니다. +경로와 파일 이름을 확인하십시오. + + + %1 already exists. +Do you want to replace it? + %1이(가) 이미 존재합니다. +바꾸시겠습니까? + + + %1 +File not found. +Please verify the correct file name was given. + %1 +파일을 찾을 수 없습니다. +경로와 파일 이름을 확인하십시오. + + + New Folder + 새 폴더 + + + '%1' is write protected. +Do you want to delete it anyway? + '%1'이(가) 쓰기 금지되어 있습니다. +그래도 삭제하시겠습니까? + + + Are sure you want to delete '%1'? + '%1'을(를) 삭제하시겠습니까? + + + Could not delete directory. + 디렉터리를 삭제할 수 없습니다. + + + Recent Places + 최근 장소 + + + Recent Places + label for first item in the menu that appears when clicking on the search field image, used as embedded menu title + 최근 장소 + + + All Files (*.*) + 모든 파일 (*) + + + Remove + 삭제 + + + My Computer + 내 컴퓨터 + + + Drive + 드라이브 + + + File + 파일 + + + File Folder + Match Windows Explorer + 파일 폴더 + + + Folder + All other platforms + 폴더 + + + Alias + Mac OS X Finder + 별명 + + + File Folder + 파일 폴더 + + + Folder + 폴더 + + + Alias + 별명 + + + Shortcut + All other platforms + 바로 가기 + + + Unknown + 알 수 없음 + + + Go forward + 앞으로 가기 + + + + QFileSystemModel + + %1 TB + %1 TB + + + %1 GB + %1 GB + + + %1 MB + %1 MB + + + %1 KB + %1 KB + + + %1 bytes + %1바이트 + + + Invalid filename + 잘못된 파일 이름 + + + <b>The name "%1" can not be used.</b><p>Try using another name, with fewer characters or no punctuations marks. + <b>"%1" 이름을 사용할 수 없습니다.</b><p>다른 이름을 사용하거나, 글자 수를 줄이거나, 구두점을 사용하지 마십시오. + + + Name + 이름 + + + Size + 크기 + + + Kind + Match OS X Finder + 형식 + + + Type + All other platforms + 형식 + + + Type + 종류 + + + Date Modified + 수정한 날짜 + + + My Computer + 내 컴퓨터 + + + Computer + 컴퓨터 + + + %1 byte(s) + %1바이트 + + + + QFontDatabase + + Normal + 일반 + + + Bold + 굵게 + + + Demi Bold + 데미볼드 + + + Black + 블랙 + + + Demi + 데미 + + + Light + 라이트 + + + Italic + 이탤릭 + + + Oblique + 기울임꼴 + + + Any + 임의 + + + Latin + 라틴 + + + Greek + 그리스 + + + Cyrillic + 키릴 + + + Armenian + 아르메니아 + + + Hebrew + 히브리 + + + Arabic + 아랍 + + + Syriac + 시리아 + + + Thaana + 타나 + + + Devanagari + 데바나가리 + + + Bengali + 벵골 + + + Gurmukhi + 굴묵키 + + + Gujarati + 구자라트 + + + Oriya + 오리야 + + + Tamil + 타밀 + + + Telugu + 텔루구 + + + Kannada + 칸나다 + + + Malayalam + 말라얄람 + + + Sinhala + 신할라 + + + Thai + 타이 + + + Lao + 라오 + + + Tibetan + 티베트 + + + Myanmar + 미얀마 + + + Georgian + 조지아 + + + Khmer + 크메르 + + + Simplified Chinese + 중국어 간체 + + + Traditional Chinese + 중국어 번체 + + + Japanese + 가나 + + + Korean + 한글 + + + Vietnamese + 베트남 + + + Symbol + 기호 + + + Ogham + 오검 + + + Runic + + + + N'Ko + 은코 + + + + QFontDialog + + Select Font + 글꼴 선택 + + + &Font + 글꼴(&F) + + + Font st&yle + 글꼴 스타일(&Y) + + + &Size + 크기(&S) + + + Effects + 효과 + + + Stri&keout + 취소선(&K) + + + &Underline + 밑줄(&U) + + + Sample + 미리 보기 + + + Wr&iting System + 문자 체계(&I) + + + + QFtp + + Not connected + 연결되지 않음 + + + Host %1 not found + 호스트 %1을(를) 찾을 수 없음 + + + Connection refused to host %1 + 호스트 %1와(과)의 연결이 거부됨 + + + Connection timed out to host %1 + 호스트 %1와(과)의 연결 시간이 초과됨 + + + Connected to host %1 + 호스트 %1에 연결이 거부됨 + + + Connection refused for data connection + 데이터 연결이 거부됨 + + + Unknown error + 알 수 없는 오류 + + + Connecting to host failed: +%1 + 호스트 연결 실패: +%1 + + + Login failed: +%1 + 로그인 실패: +%1 + + + Listing directory failed: +%1 + 디렉터리 목록 표시 실패: +%1 + + + Changing directory failed: +%1 + 디렉터리 변경 실패: +%1 + + + Downloading file failed: +%1 + 파일 다운로드 실패: +%1 + + + Uploading file failed: +%1 + 파일 업로드 실패: +%1 + + + Removing file failed: +%1 + 파일 삭제 실패: +%1 + + + Creating directory failed: +%1 + 디렉터리 생성 실패: +%1 + + + Removing directory failed: +%1 + 디렉터리 삭제 실패: +%1 + + + Connection closed + 연결이 종료됨 + + + Host %1 found + 호스트 %1을(를) 찾았음 + + + Connection to %1 closed + %1와(과)의 연결이 종료됨 + + + Host found + 호스트를 찾았음 + + + Connected to host + 호스트에 연결됨 + + + + QHostInfo + + No host name given + 호스트 이름이 지정되지 않음 + + + Unknown error + 알 수 없는 오류 + + + + QHostInfoAgent + + No host name given + 호스트 이름이 지정되지 않았음 + + + Invalid hostname + 호스트 이름이 잘못됨 + + + Unknown address type + 알 수 없는 주소 형식 + + + Host not found + 호스트를 찾을 수 없음 + + + Unknown error + 알 수 없는 오류 + + + + QHttp + + HTTPS connection requested but SSL support not compiled in + HTTPS 연결을 요청했지만 SSL 지원을 사용할 수 없음 + + + Unknown error + 알 수 없는 오류 + + + Request aborted + 요청이 중단됨 + + + No server set to connect to + 연결할 서버가 설정되지 않음 + + + Wrong content length + 내용 길이가 잘못됨 + + + Server closed connection unexpectedly + 서버에서 예상하지 못하게 연결을 종료함 + + + Connection refused (or timed out) + 연결이 거부됨 (또는 시간 초과됨) + + + Host %1 not found + 호스트 %1을(를) 찾을 수 없음 + + + HTTP request failed + HTTP 요청이 실패함 + + + Invalid HTTP response header + HTTP 응답 헤더가 잘못됨 + + + Unknown authentication method + 알 수 없는 인증 방법 + + + Proxy authentication required + 프록시 인증이 필요함 + + + Authentication required + 인증이 필요함 + + + Invalid HTTP chunked body + HTTP 조각난 본문이 잘못됨 + + + Error writing response to device + 장치에 응답을 쓰는 중 오류 발생 + + + Connection refused + 연결이 거부됨 + + + Connection closed + 연결이 종료됨 + + + Proxy requires authentication + 프록시 인증이 필요함 + + + Host requires authentication + 호스트 인증이 필요함 + + + Data corrupted + 데이터 손상됨 + + + Unknown protocol specified + 알 수 없는 프로토콜 + + + SSL handshake failed + SSL 악수 실패 + + + Host %1 found + 호스트 %1을(를) 찾았음 + + + Connected to host %1 + 호스트 %1에 연결됨 + + + Connection to %1 closed + %1와(과)의 연결이 종료됨 + + + Host found + 호스트를 찾았음 + + + Connected to host + 호스트에 연결됨 + + + + QHttpSocketEngine + + Did not receive HTTP response from proxy + 프록시에서 HTTP 응답을 받지 못함 + + + Error parsing authentication request from proxy + 프록시 인증을 처리하는 중 오류 발생 + + + Authentication required + 인증이 필요함 + + + Proxy denied connection + 프록시에서 연결 거부됨 + + + Error communicating with HTTP proxy + HTTP 프록시와 통신하는 중 오류 발생 + + + Proxy server not found + 프록시 서버를 찾을 수 없음 + + + Proxy connection refused + 프록시 서버에 연결이 거부됨 + + + Proxy server connection timed out + 프록시 서버 연결 시간 초과됨 + + + Proxy connection closed prematurely + 프록시 서버 연결이 일찍 종료됨 + + + + QIBaseDriver + + Error opening database + 데이터베이스를 여는 중 오류 발생 + + + Could not start transaction + 트랙잭션을 시작할 수 없음 + + + Unable to commit transaction + 트랜잭션을 커밋할 수 없음 + + + Unable to rollback transaction + 트랜잭션을 되돌릴 수 없음 + + + + QIBaseResult + + Unable to create BLOB + BLOB을 만들 수 없음 + + + Unable to write BLOB + BLOB에 쓸 수 없음 + + + Unable to open BLOB + BLOB을 열 수 없음 + + + Unable to read BLOB + BLOB에서 읽을 수 없음 + + + Could not find array + 배열을 찾을 수 없음 + + + Could not get array data + 배열 데이터를 가져올 수 없음 + + + Could not get query info + 쿼리 정보를 가져올 수 없음 + + + Could not start transaction + 트랜잭션을 시작할 수 없음 + + + Unable to commit transaction + 트랜잭션을 커밋할 수 없음 + + + Could not allocate statement + 구문을 할당할 수 없음 + + + Could not prepare statement + 구문을 준비할 수 없음 + + + Could not describe input statement + 입력 구문을 설명할 수 없음 + + + Could not describe statement + 구문을 설명할 수 없음 + + + Unable to close statement + 구문을 닫을 수 없음 + + + Unable to execute query + 쿼리를 실행할 수 없음 + + + Could not fetch next item + 다음 항목을 가져올 수 없음 + + + Could not get statement info + 구문 정보를 가져올 수 없음 + + + + QIODevice + + Permission denied + 권한이 거부됨 + + + Too many open files + 너무 많은 파일이 열렸음 + + + No such file or directory + 그러한 파일이나 디렉터리가 없음 + + + No space left on device + 장치에 공간이 부족함 + + + Unknown error + 알 수 없는 오류 + + + + QInputContext + + XIM + XIM + + + FEP + FEP + + + XIM input method + XIM 입력기 + + + Windows input method + 윈도 입력기 + + + Mac OS X input method + Mac OS X 입력기 + + + S60 FEP input method + S60 FEP 입력기 + + + + QInputDialog + + Enter a value: + 값을 입력하십시오: + + + + QLibrary + + Plugin verification data mismatch in '%1' + '%1'의 플러그인 확인 데이터가 일치하지 않음 + + + The shared library was not found. + 공유 라이브러리를 찾을 수 없습니다. + + + The file '%1' is not a valid Qt plugin. + 파일 '%1'은(는) 올바른 Qt 플러그인이 아닙니다. + + + The plugin '%1' uses incompatible Qt library. (%2.%3.%4) [%5] + 플러그인 '%1'은(는) 호환되지 않는 Qt 라이브러리를 사용합니다. (%2.%3.%4) [%5] + + + The plugin '%1' uses incompatible Qt library. Expected build key "%2", got "%3" + 플러그인 '%1'은(는) 호환되지 않는 Qt 라이브러리를 사용합니다. 빌드 키 "%2"을(를) 예상했지만 "%3"이(가) 돌아왔습니다 + + + The plugin '%1' uses incompatible Qt library. (Cannot mix debug and release libraries.) + 플러그인 '%1'은(는) 호환되지 않는 Qt 라이브러리를 사용합니다. (디버그와 릴리즈 라이브러리를 섞을 수 없습니다.) + + + Unknown error + 알 수 없는 오류 + + + Cannot load library %1: %2 + 라이브러리 %1을(를) 불러올 수 없음: %2 + + + Cannot unload library %1: %2 + 라이브러리 %1을(를) 닫을 수 없음: %2 + + + Cannot resolve symbol "%1" in %2: %3 + %2의 심볼 "%1"을(를) 불러올 수 없음: %3 + + + + QLineEdit + + &Undo + 실행 취소(&U) + + + &Redo + 다시 실행(&R) + + + Cu&t + 잘라내기(&T) + + + &Copy + 복사(&C) + + + &Paste + 붙여넣기(&P) + + + Delete + 삭제 + + + Select All + 모두 선택 + + + + QLocalServer + + %1: Name error + %1: 이름 오류 + + + %1: Permission denied + %1: 권한이 거부됨 + + + %1: Address in use + %1: 주소가 사용 중 + + + %1: Unknown error %2 + %1: 알 수 없는 오류 %2 + + + + QLocalSocket + + %1: Connection refused + %1: 연결이 거부됨 + + + %1: Remote closed + %1: 원격 호스트가 연결 닫음 + + + %1: Invalid name + %1: 잘못된 이름 + + + %1: Socket access error + %1: 소켓 접근 오류 + + + %1: Socket resource error + %1: 소켓 자원 오류 + + + %1: Socket operation timed out + %1: 소켓 작업 시간 초과됨 + + + %1: Datagram too large + %1: 데이터그램이 너무 큼 + + + %1: Connection error + %1: 연결 오류 + + + %1: The socket operation is not supported + %1: 소켓 작업이 지원되지 않음 + + + %1: Unknown error + %1: 알 수 없는 오류 + + + %1: Unknown error %2 + %1: 알 수 없는 오류 %2 + + + + QMYSQLDriver + + Unable to open database ' + 다음 데이터베이스를 열 수 없음: ' + + + Unable to connect + 연결할 수 없음 + + + Unable to begin transaction + 트랜잭션을 시작할 수 없음 + + + Unable to commit transaction + 트랜잭션을 커밋할 수 없음 + + + Unable to rollback transaction + 트랜잭션을 되돌릴 수 없음 + + + + QMYSQLResult + + Unable to fetch data + 데이터를 가져올 수 없음 + + + Unable to execute query + 쿼리를 실행할 수 없음 + + + Unable to store result + 결과를 저장할 수 없음 + + + Unable to execute next query + 다음 쿼리를 실행할 수 없음 + + + Unable to store next result + 다음 결과를 저장할 수 없음 + + + Unable to prepare statement + 구문을 준비할 수 없음 + + + Unable to reset statement + 구문을 초기화할 수 없음 + + + Unable to bind value + 값을 바인딩할 수 없음 + + + Unable to execute statement + 구문을 실행할 수 없음 + + + Unable to bind outvalues + outvalue를 바인딩할 수 없음 + + + Unable to store statement results + 구문 실행 결과를 저장할 수 없음 + + + + QMdiArea + + (Untitled) + (제목 없음) + + + + QMdiSubWindow + + - [%1] + - [%1] + + + %1 - [%2] + %1 - [%2] + + + Minimize + 최소화 + + + Maximize + 최대화 + + + Unshade + 풀어 내리기 + + + Shade + 말아 올리기 + + + Restore Down + 복원 + + + Restore + 복원 + + + Close + 닫기 + + + Help + 도움말 + + + Menu + 메뉴 + + + &Restore + 복원(&R) + + + &Move + 이동(&M) + + + &Size + 크기(&S) + + + Mi&nimize + 최소화(&N) + + + Ma&ximize + 최대화(&X) + + + Stay on &Top + 항상 위(&T) + + + &Close + 닫기(&C) + + + + QMenu + + Close + 닫기 + + + Open + 열기 + + + Execute + 실행 + + + + QMenuBar + + Actions + 동작 + + + + QMessageBox + + Show Details... + 자세한 정보 보기... + + + Hide Details... + 자세한 정보 숨기기... + + + OK + 확인 + + + Help + 도움말 + + + <h3>About Qt</h3><p>This program uses Qt version %1.</p> + <h3>Qt 정보</h3><p>이 프로그램은 Qt 버전 %1을(를) 사용합니다.</p> + + + <p>Qt is a C++ toolkit for cross-platform application development.</p><p>Qt provides single-source portability across MS&nbsp;Windows, Mac&nbsp;OS&nbsp;X, Linux, and all major commercial Unix variants. Qt is also available for embedded devices as Qt for Embedded Linux and Qt for Windows CE.</p><p>Qt is available under three different licensing options designed to accommodate the needs of our various users.</p><p>Qt licensed under our commercial license agreement is appropriate for development of proprietary/commercial software where you do not want to share any source code with third parties or otherwise cannot comply with the terms of the GNU LGPL version 2.1 or GNU GPL version 3.0.</p><p>Qt licensed under the GNU LGPL version 2.1 is appropriate for the development of Qt applications (proprietary or open source) provided you can comply with the terms and conditions of the GNU LGPL version 2.1.</p><p>Qt licensed under the GNU General Public License version 3.0 is appropriate for the development of Qt applications where you wish to use such applications in combination with software subject to the terms of the GNU GPL version 3.0 or where you are otherwise willing to comply with the terms of the GNU GPL version 3.0.</p><p>Please see <a href="http://qt.nokia.com/products/licensing">qt.nokia.com/products/licensing</a> for an overview of Qt licensing.</p><p>Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).</p><p>Qt is a Nokia product. See <a href="http://qt.nokia.com/">qt.nokia.com</a> for more information.</p> + <p>Qt는 크로스 플랫폼 프로그램 개발을 위한 C++ 툴킷입니다.</p><p>Qt는 마이크로소프트&nbsp;윈도, Mac&nbsp;OS&nbsp;X, 리눅스, 여러 상용 유닉스 간 소스 호환성을 제공합니다. Qt는 Qt for Embedded Linux, Qt for Windows CE와 같은 임베디드 장치도 지원합니다.</p><p>Qt는 여러 사용자의 조건에 맞는 세 가지 조건으로 라이선스됩니다.</p><p>Qt의 상용 라이선스는 제 3자와 코드를 공유할 수 없거나, GNU LGPL 2.1, GNU GPL 3.0의 조건을 따를 수 없는 독점/상용 소프트웨어 개발에 사용할 수 있습니다.</p><p>Qt의 GNU LGPL 2.1 라이선스는 GNU LGPL 2.1의 조건을 따르는 독점 및 오픈소스 Qt 프로그램을 개발할 수 있습니다.</p><p>Qt의 GNU GPL 3.0 라이선스는 GNU GPL 3.0의 조건을 적용받거나 GNU GPL 3.0으로 라이선싱할 Qt 프로그램을 개발할 수 있습니다.</p><p>Qt 라이선싱 조건을 알아 보려면 <a href="http://qt.nokia.con/products/licensing">qt.nokia.com/products/licensing</a> 페이지를 참고하십시오.</p><p>Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).</p><p>Qt는 노키아의 제품입니다. 더 많은 정보를 보려면 <a href="http://qt.nokia.com">qt.nokia.com</a>을 참조하십시오.</p> + + + About Qt + Qt 정보 + + + + QMultiInputContext + + Select IM + 입력기 선택 + + + + QMultiInputContextPlugin + + Multiple input method switcher + 다중 입력기 전환기 + + + Multiple input method switcher that uses the context menu of the text widgets + 텍스트 위젯의 컨텍스트 메뉴를 사용하는 다중 입력기 전환기 + + + + QNativeSocketEngine + + Unable to initialize non-blocking socket + 논블러킹 소켓을 초기화할 수 없음 + + + Unable to initialize broadcast socket + 브로드캐스트 소켓을 초기화할 수 없음 + + + Attempt to use IPv6 socket on a platform with no IPv6 support + IPv6을 지원하지 않는 플랫폼에서 IPv6 소켓을 사용하려고 시도함 + + + The remote host closed the connection + 원격 호스트에서 연결을 닫음 + + + Network operation timed out + 네트워크 작업 시간 초과 + + + Out of resources + 자원 부족 + + + Unsupported socket operation + 지원하지 않는 소켓 작업 + + + Protocol type not supported + 지원하지 않는 프로토콜 형식 + + + Invalid socket descriptor + 잘못된 소켓 설명자 + + + Host unreachable + 호스트에 접근할 수 없음 + + + Network unreachable + 네트워크에 접근할 수 없음 + + + Permission denied + 권한이 거부됨 + + + Connection timed out + 연결 시간 초과됨 + + + Connection refused + 연결이 거부됨 + + + The bound address is already in use + 지정한 주소가 이미 사용 중 + + + The address is not available + 주소를 사용할 수 없음 + + + The address is protected + 주소가 보호되어 있음 + + + Datagram was too large to send + 한 번에 보낼 데이터그램이 너무 큼 + + + Unable to send a message + 메시지를 보낼 수 없음 + + + Unable to receive a message + 메시지를 받을 수 없음 + + + Unable to write + 쓸 수 없음 + + + Network error + 네트워크 오류 + + + Another socket is already listening on the same port + 다른 소켓이 지정한 포트에서 듣고 있음 + + + Operation on non-socket + 비 소켓에서 작업 실행됨 + + + The proxy type is invalid for this operation + 이 작업에 사용할 프록시 형식이 잘못되었습니다 + + + Unknown error + 알 수 없는 오류 + + + + QNetworkAccessCacheBackend + + Error opening %1 + %1을(를) 여는 중 오류 발생 + + + + QNetworkAccessDataBackend + + Operation not supported on %1 + %1에는 작업이 지원되지 않음 + + + Invalid URI: %1 + 잘못된 URI: %1 + + + + QNetworkAccessDebugPipeBackend + + Write error writing to %1: %2 + %1에 쓰는 중 오류 발생: %2 + + + Socket error on %1: %2 + %1에서 소켓 오류 발생: %2 + + + Remote host closed the connection prematurely on %1 + %1에서 원격 호스트가 일찍 연결을 닫음 + + + + QNetworkAccessFileBackend + + Request for opening non-local file %1 + 비 로컬 파일 %1을(를) 여는 요청 들어옴 + + + Cannot open %1: Path is a directory + %1을(를) 열 수 없음: 디렉터리임 + + + Error opening %1: %2 + %1을(를) 여는 중 오류 발생: %2 + + + Write error writing to %1: %2 + %1에 쓰는 중 오류 발생: %2 + + + Read error reading from %1: %2 + %1에서 읽는 중 오류 발생: %2 + + + + QNetworkAccessFtpBackend + + No suitable proxy found + 적합한 프록시를 찾을 수 없음 + + + Cannot open %1: is a directory + %1을(를) 열 수 없음: 디렉터리임 + + + Logging in to %1 failed: authentication required + %1에 로그인할 수 없음: 인증 필요함 + + + Error while downloading %1: %2 + %1 다운로드 중 오류 발생: %2 + + + Error while uploading %1: %2 + %1 업로드 중 오류 발생: %2 + + + + QNetworkAccessHttpBackend + + No suitable proxy found + 적합한 프록시를 찾을 수 없음 + + + + QNetworkAccessManager + + Network access is disabled. + 네트워크 접근이 비활성화되었습니다. + + + + QNetworkReply + + Error downloading %1 - server replied: %2 + %1을(를) 다운로드하는 중 오류 발생 - 서버 응답: %2 + + + Protocol "%1" is unknown + 알 수 없는 프로토콜 "%1" + + + Network session error. + 네트워크 세션 오류. + + + Temporary network failure. + 일시적인 네트워크 실패. + + + + QNetworkReplyImpl + + Operation canceled + 작업 취소됨 + + + + QNetworkSession + + Invalid configuration. + 설정이 잘못되었습니다. + + + + QNetworkSessionPrivateImpl + + Roaming error + 로밍 오류 + + + Session aborted by user or system + 사용자나 시스템에서 세션 종료함 + + + The specified configuration cannot be used. + 지정한 설정을 사용할 수 없습니다. + + + Unidentified Error + 지정되지 않은 오류 + + + Unknown session error. + 알 수 없는 세션 오류. + + + The session was aborted by the user or system. + 사용자나 시스템에서 세션을 중단하였습니다. + + + The requested operation is not supported by the system. + 시스템에서 요청한 구성을 지원하지 않습니다. + + + Roaming was aborted or is not possible. + 로밍이 중단되었거나 사용할 수 없습니다. + + + + QOCIDriver + + Unable to initialize + QOCIDriver + 초기화할 수 없음 + + + Unable to logon + 로그온할 수 없음 + + + Unable to begin transaction + 트랜잭션을 시작할 수 없음 + + + Unable to commit transaction + 트랜잭션을 커밋할 수 없음 + + + Unable to rollback transaction + 트랜잭션을 되돌릴 수 없음 + + + + QOCIResult + + Unable to bind column for batch execute + 배치 실행의 열을 바인딩할 수 없음 + + + Unable to execute batch statement + 배치 구문을 실행할 수 없음 + + + Unable to goto next + 다음으로 이동할 수 없음 + + + Unable to alloc statement + 구문을 할당할 수 없음 + + + Unable to prepare statement + 구문을 준비할 수 없음 + + + Unable to get statement type + 구문 형식을 가져올 수 없음 + + + Unable to bind value + 값을 바인딩할 수 없음 + + + Unable to execute statement + 구문을 실행할 수 없음 + + + + QODBCDriver + + Unable to connect + 연결할 수 없음 + + + Unable to connect - Driver doesn't support all functionality required + 연결할 수 없음 - 드라이버가 모든 필요한 기능을 제공하지 않습니다 + + + Unable to disable autocommit + 자동 커밋을 해제할 수 없음 + + + Unable to commit transaction + 트랜잭션을 커밋할 수 없음 + + + Unable to rollback transaction + 트랜잭션을 되돌릴 수 없음 + + + Unable to enable autocommit + 자동 커밋을 설정할 수 없음 + + + + QODBCResult + + Unable to fetch last + 마지막 항목을 가져올 수 없음 + + + QODBCResult::reset: Unable to set 'SQL_CURSOR_STATIC' as statement attribute. Please check your ODBC driver configuration + QODBCResult::reset: 'SQL_CURSOR_STATIC'을 구문 속성으로 설정할 수 없음. ODBC 드라이버의 설정을 확인하십시오 + + + Unable to execute statement + 구문을 실행할 수 없음 + + + Unable to fetch + 항목을 가져올 수 없음 + + + Unable to fetch next + 다음 항목을 가져올 수 없음 + + + Unable to fetch first + 이전 항목을 가져올 수 없음 + + + Unable to fetch previous + 이전 항목을 가져올 수 없음 + + + Unable to prepare statement + 구문을 준비할 수 없음 + + + Unable to bind variable + 변수를 바인딩할 수 없음 + + + + QObject + + PulseAudio Sound Server + PulseAudio 소리 서버 + + + "%1" duplicates a previous role name and will be disabled. + "%1"이(가) 이전 역할 이름과 중복되므로 비활성화될 것입니다. + + + invalid query: "%1" + 잘못된 쿼리: "%1" + + + + QPPDOptionsModel + + Name + 이름 + + + Value + + + + + QPSQLDriver + + Unable to connect + 연결할 수 없음 + + + Could not begin transaction + 트랙잭션을 시작할 수 없음 + + + Could not commit transaction + 트랙잭션을 커밋할 수 없음 + + + Could not rollback transaction + 트랙잭션을 되돌릴 수 없음 + + + Unable to subscribe + 등록할 수 없음 + + + Unable to unsubscribe + 등록 해제할 수 없음 + + + + QPSQLResult + + Unable to create query + 쿼리를 만들 수 없음 + + + Unable to prepare statement + 구문을 준비할 수 없음 + + + + QPageSetupWidget + + Form + + + + Paper + 종이 + + + Page size: + 쪽 크기: + + + Width: + 너비: + + + Height: + 높이: + + + Paper source: + 종이 공급: + + + Orientation + 방향 + + + Portrait + 세로 + + + Landscape + 가로 + + + Reverse landscape + 뒤집은 가로 + + + Reverse portrait + 뒤집은 세로 + + + Margins + 여백 + + + top margin + 위쪽 여백 + + + left margin + 왼쪽 여백 + + + right margin + 오른쪽 여백 + + + bottom margin + 아래쪽 여백 + + + Centimeters (cm) + 센티미터 (cm) + + + Millimeters (mm) + 밀리미터 (mm) + + + Inches (in) + 인치 (in) + + + Points (pt) + 포인트 (pt) + + + + QPluginLoader + + The plugin was not loaded. + 플러그인을 불러오지 못했습니다. + + + Unknown error + 알 수 없는 오류 + + + + QPrintDialog + + Print + 인쇄 + + + A0 + A0 + + + A1 + A1 + + + A2 + A2 + + + A3 + A3 + + + A4 + A4 + + + A5 + A5 + + + A6 + A6 + + + A7 + A7 + + + A8 + A8 + + + A9 + A9 + + + B0 + B0 + + + B1 + B1 + + + B2 + B2 + + + B3 + B3 + + + B4 + B4 + + + B5 + B5 + + + B6 + B6 + + + B7 + B7 + + + B8 + B8 + + + B9 + B9 + + + B10 + B10 + + + C5E + C5E + + + DLE + DLE + + + Executive + Executive + + + Folio + 폴리오 + + + Ledger + 레저 + + + Legal + 리갈 + + + Letter + 레터 + + + Tabloid + 타블로이드 + + + US Common #10 Envelope + 미국 공용 봉투 #10 + + + Custom + 사용자 정의 + + + File exists + 파일이 존재함 + + + <qt>Do you want to overwrite it?</qt> + <qt>덮어쓰시겠습니까?</qt> + + + A0 (841 x 1189 mm) + A0 (841 x 1189 mm) + + + A1 (594 x 841 mm) + A1 (594 x 841 mm) + + + A2 (420 x 594 mm) + A2 (420 x 594 mm) + + + A3 (297 x 420 mm) + A3 (297 x 420 mm) + + + A4 (210 x 297 mm, 8.26 x 11.7 inches) + A4 (210 x 297 mm, 8.26 x 11.7 인치) + + + A5 (148 x 210 mm) + A5 (148 x 210 mm) + + + A6 (105 x 148 mm) + A6 (105 x 148 mm) + + + A7 (74 x 105 mm) + A7 (74 x 105 mm) + + + A8 (52 x 74 mm) + A8 (52 x 74 mm) + + + A9 (37 x 52 mm) + A9 (37 x 52 mm) + + + B0 (1000 x 1414 mm) + B0 (1000 x 1414 mm) + + + B1 (707 x 1000 mm) + B1 (707 x 1000 mm) + + + B2 (500 x 707 mm) + B2 (500 x 707 mm) + + + B3 (353 x 500 mm) + B3 (353 x 500 mm) + + + B4 (250 x 353 mm) + B4 (250 x 353 mm) + + + B5 (176 x 250 mm, 6.93 x 9.84 inches) + B5 (176 x 250 mm, 6.93 x 9.84 인치) + + + B6 (125 x 176 mm) + B6 (125 x 176 mm) + + + B7 (88 x 125 mm) + B7 (88 x 125 mm) + + + B8 (62 x 88 mm) + B8 (62 x 88 mm) + + + B9 (44 x 62 mm) + B9 (44 x 62 mm) + + + B10 (31 x 44 mm) + B10 (31 x 44 mm) + + + C5E (163 x 229 mm) + C5E (163 x 229 mm) + + + DLE (110 x 220 mm) + DLE (110 x 220 mm) + + + Executive (7.5 x 10 inches, 191 x 254 mm) + Executive (7.5 x 10 인치, 191 x 254 mm) + + + Folio (210 x 330 mm) + 폴리오 (210 x 330 mm) + + + Ledger (432 x 279 mm) + 레저 (432 x 279 mm) + + + Legal (8.5 x 14 inches, 216 x 356 mm) + 리갈 (8.5 x 14 인치, 216 x 356 mm) + + + Letter (8.5 x 11 inches, 216 x 279 mm) + 레터 (8.5 x 11 인치, 216 x 279 mm) + + + Tabloid (279 x 432 mm) + 타블로이드 (279 x 432 mm) + + + US Common #10 Envelope (105 x 241 mm) + 미국 공용 봉투 #10 (105 x 241 mm) + + + Print all + 모두 인쇄 + + + Print selection + 선택 영역만 인쇄 + + + Print range + 인쇄 범위 + + + Print current page + 현재 쪽 인쇄 + + + &Options >> + 설정(&O) >> + + + &Print + 인쇄(&P) + + + &Options << + 설정(&O) << + + + Print to File (PDF) + 파일로 인쇄 (PDF) + + + Print to File (Postscript) + 파일로 인쇄 (포스트스크립트) + + + Local file + 로컬 파일 + + + Write %1 file + %1 파일로 쓰기 + + + Print To File ... + 파일로 인쇄... + + + %1 is a directory. +Please choose a different file name. + %1은(는) 디렉터리입니다. +다른 파일 이름을 선택하십시오. + + + File %1 is not writable. +Please choose a different file name. + 파일 %1에 쓸 수 없습니다. +다른 파일 이름을 선택하십시오. + + + %1 already exists. +Do you want to overwrite it? + %1이(가) 이미 존재합니다. +덮어쓰시겠습니까? + + + The 'From' value cannot be greater than the 'To' value. + '시작' 값이 '끝' 값보다 클 수 없습니다. + + + OK + 확인 + + + locally connected + 로컬로 연결됨 + + + Aliases: %1 + 별명: %1 + + + unknown + 알 수 없음 + + + + QPrintPreviewDialog + + Page Setup + 쪽 설정 + + + %1% + %1% + + + Print Preview + 인쇄 미리 보기 + + + Next page + 다음 쪽 + + + Previous page + 이전 쪽 + + + First page + 첫 쪽 + + + Last page + 마지막 쪽 + + + Fit width + 폭 맞춤 + + + Fit page + 쪽 맞춤 + + + Zoom in + 확대 + + + Zoom out + 축소 + + + Portrait + 세로 + + + Landscape + 가로 + + + Show single page + 한 쪽 보이기 + + + Show facing pages + 맞쪽 보기 + + + Show overview of all pages + 전체 쪽 보기 + + + Print + 인쇄 + + + Page setup + 쪽 설정 + + + Close + 닫기 + + + Export to PDF + PDF로 내보내기 + + + Export to PostScript + 포스트스크립트로 내보내기 + + + + QPrintPropertiesWidget + + Form + + + + Page + + + + Advanced + 고급 + + + + QPrintSettingsOutput + + Form + + + + Copies + 복사 부수 + + + Print range + 인쇄 범위 + + + Print all + 모두 인쇄 + + + Pages from + 시작 쪽 + + + to + 끝 쪽 + + + Current Page + 현재 쪽 + + + Selection + 선택 + + + Output Settings + 출력 설정 + + + Copies: + 복사 부수: + + + Collate + 한 부씩 인쇄 + + + Reverse + 역순 인쇄 + + + Options + 옵션 + + + Color Mode + 색 모드 + + + Color + 색상 + + + Grayscale + 그레이스케일 + + + Duplex Printing + 양면 인쇄 + + + None + 없음 + + + Long side + 긴 쪽 + + + Short side + 짧은 쪽 + + + + QPrintWidget + + Form + + + + Printer + 프린터 + + + &Name: + 이름(&N): + + + P&roperties + 속성(&R) + + + Location: + 위치: + + + Preview + 미리 보기 + + + Type: + 종류: + + + Output &file: + 출력 파일(&F): + + + ... + ... + + + + QProcess + + Error reading from process + 프로세스에서 읽을 수 없음 + + + Error writing to process + 프로세스에 쓸 수 없음 + + + Process crashed + 프로세스가 충돌함 + + + No program defined + 프로그램이 지정되지 않음 + + + Could not open input redirection for reading + 읽기 위해 입력 리다이렉션을 열 수 없음 + + + Could not open output redirection for writing + 쓰기 위해 출력 리다이렉션을 열 수 없음 + + + Resource error (fork failure): %1 + 자원 오류 (fork 실패): %1 + + + Process operation timed out + 프로세스 작업 시간 초과 + + + Process failed to start: %1 + 프로세스를 시작할 수 없음: %1 + + + + QProgressDialog + + Cancel + 취소 + + + + QPushButton + + Open + 열기 + + + + QRadioButton + + Check + 선택 + + + + QRegExp + + no error occurred + 오류 없음 + + + disabled feature used + 비활성화된 기능 사용됨 + + + bad char class syntax + 잘못된 문자열 클래스 문법 + + + bad lookahead syntax + 잘못된 룩어헤드 문법 + + + bad repetition syntax + 잘못된 반복 문법 + + + invalid octal value + 잘못된 8진 값 + + + missing left delim + 왼쪽 구분자 없음 + + + unexpected end + 예상하지 못한 끝 + + + met internal limit + 내부 한계에 도달함 + + + invalid interval + 잘못된 간격 + + + invalid category + 잘못된 분류 + + + + QSQLite2Driver + + Error opening database + 데이터베이스를 여는 중 오류 발생 + + + Unable to begin transaction + 트랜잭션을 시작할 수 없음 + + + Unable to commit transaction + 트랜잭션을 커밋할 수 없음 + + + Unable to rollback transaction + 트랜잭션을 되돌릴 수 없음 + + + + QSQLite2Result + + Unable to fetch results + 결과를 가져올 수 없음 + + + Unable to execute statement + 구문을 실행할 수 없음 + + + + QSQLiteDriver + + Error opening database + 데이터베이스를 여는 중 오류 발생 + + + Error closing database + 데이터베이스를 닫는 중 오류 발생 + + + Unable to begin transaction + 트랜잭션을 시작할 수 없음 + + + Unable to commit transaction + 트랜잭션을 커밋할 수 없음 + + + Unable to rollback transaction + 트랜잭션을 되돌릴 수 없음 + + + + QSQLiteResult + + Unable to fetch row + 열을 가져올 수 없음 + + + No query + 쿼리 없음 + + + Unable to execute statement + 구문을 실행할 수 없음 + + + Unable to reset statement + 구문을 초기화할 수 없음 + + + Unable to bind parameters + 인자를 바인딩할 수 없음 + + + Parameter count mismatch + 인자 수가 일치하지 않음 + + + + QScriptBreakpointsModel + + ID + ID + + + Location + 위치 + + + Condition + 조건 + + + Ignore-count + 무시 개수 + + + Single-shot + 싱글 샷 + + + Hit-count + 일치 개수 + + + + QScriptBreakpointsWidget + + New + 새로 만들기 + + + Delete + 삭제 + + + + QScriptDebugger + + Go to Line + 줄로 가기 + + + Line: + 줄: + + + Interrupt + 인터럽트 + + + Shift+F5 + Shift+F5 + + + Continue + 계속 + + + F5 + F5 + + + Step Into + 안으로 들어가기 + + + F11 + F11 + + + Step Over + 넘어가기 + + + F10 + F10 + + + Step Out + 빠져 나가기 + + + Shift+F11 + Shift+F11 + + + Run to Cursor + 커서까지 실행 + + + Ctrl+F10 + Ctrl+F10 + + + Run to New Script + 새 스크립트까지 실행 + + + Toggle Breakpoint + 중단점 지정/해제 + + + F9 + F9 + + + Clear Debug Output + 디버그 출력 삭제 + + + Clear Error Log + 오류 로그 삭제 + + + Clear Console + 콘솔 삭제 + + + &Find in Script... + 스크립트에서 찾기(&F)... + + + Ctrl+F + Ctrl+F + + + Find &Next + 다음 찾기(&N) + + + F3 + F3 + + + Find &Previous + 이전 찾기(&P) + + + Shift+F3 + Shift+F3 + + + Ctrl+G + Ctrl+G + + + Debug + 디버그 + + + + QScriptDebuggerCodeFinderWidget + + Close + 닫기 + + + Previous + 이전 + + + Next + 다음 + + + Case Sensitive + 대소문자 구분 + + + Whole words + 단어 단위로 + + + <img src=":/qt/scripttools/debugging/images/wrap.png">&nbsp;Search wrapped + <img src=":/qt/scripttools/debugging/images/wrap.png">&nbsp;검색 다시 시작됨 + + + + QScriptDebuggerLocalsModel + + Name + 이름 + + + Value + + + + + QScriptDebuggerStackModel + + Level + 단계 + + + Name + 이름 + + + Location + 위치 + + + + QScriptEdit + + Toggle Breakpoint + 중단점 설정/해제 + + + Disable Breakpoint + 중단점 해제 + + + Enable Breakpoint + 중단점 설정 + + + Breakpoint Condition: + 중단점 조건: + + + + QScriptEngineDebugger + + Loaded Scripts + 불러온 스크립트 + + + Breakpoints + 중단점 + + + Stack + 스택 + + + Locals + 지역 변수 + + + Console + 콘솔 + + + Debug Output + 디버그 출력 + + + Error Log + 오류 로그 + + + Search + 검색 + + + View + 보기 + + + Qt Script Debugger + Qt 스크립트 디버거 + + + + QScriptNewBreakpointWidget + + Close + 닫기 + + + + QScrollBar + + Scroll here + 여기로 스크롤 + + + Left edge + 왼쪽 경계 + + + Top + 맨 위 + + + Right edge + 오른쪽 경계 + + + Bottom + 맨 아래 + + + Page left + 왼쪽 페이지 + + + Page up + 위쪽 페이지 + + + Page right + 오른쪽 페이지 + + + Page down + 아래쪽 페이지 + + + Scroll left + 왼쪽으로 스크롤 + + + Scroll up + 위로 스크롤 + + + Scroll right + 오른쪽으로 스크롤 + + + Scroll down + 아래로 스크롤 + + + Line up + 한 줄 위로 + + + Position + 위치 + + + Line down + 한 줄 아래로 + + + + QSharedMemory + + %1: unable to set key on lock + %1: 잠금에 키를 설정할 수 없음 + + + %1: create size is less then 0 + %1: 생성 크기가 0 미만임 + + + %1: unable to lock + %1: 잠글 수 없음 + + + %1: unable to unlock + %1: 잠금을 풀 수 없음 + + + %1: already exists + QSystemSemaphore + %1: 이미 존재함 + + + %1: doesn't exists + QSystemSemaphore + %1: 존재하지 않음 + + + %1: already exists + %1: 이미 존재함 + + + %1: doesn't exists + %1: 존재하지 않음 + + + %1: invalid size + %1: 잘못된 크기 + + + %1: out of resources + %1: 자원 부족 + + + %1: permission denied + %1: 권한이 거부됨 + + + %1: unknown error %2 + %1: 알 수 없는 오류 %2 + + + %1: unable to make key + %1: 키를 만들 수 없음 + + + %1: permission denied + QSystemSemaphore + %1: 권한이 거부됨 + + + %1: unknown error %2 + QSystemSemaphore + %1: 알 수 없는 오류 %2 + + + %1: key error + %1: 키 오류 + + + %1: unable to make key + QSystemSemaphore + %1: 키를 만들 수 없음 + + + %1: doesn't exist + QSystemSemaphore + %1: 존재하지 않음 + + + %1: key is empty + QSystemSemaphore + %1: 키가 비어 있음 + + + %1: UNIX key file doesn't exist + %1: 유닉스 키 파일이 없음 + + + %1: ftok failed + QSystemSemaphore + %1: ftok 실패 + + + %1: doesn't exist + %1: 존재하지 않음 + + + %1: key is empty + %1: 키가 비어 있음 + + + %1: ftok failed + %1: ftok 실패 + + + %1: system-imposed size restrictions + %1: 시스템에서 크게를 제한함 + + + %1: not attached + %1: 연결되지 않음 + + + %1: size query failed + QSystemSemaphore + %1: 크기 조회 실패 + + + %1: size query failed + %1: 크기 조회 실패 + + + + QShortcut + + Space + This and all following "incomprehensible" strings in QShortcut context are key names. Please use the localized names appearing on actual keyboards or whatever is commonly used. + Space + + + Esc + Esc + + + Tab + Tab + + + Backtab + Backtab + + + Backspace + Backspace + + + Return + Return + + + Enter + Enter + + + Ins + Ins + + + Del + Del + + + Pause + Pause + + + Print + Print + + + SysReq + SysReq + + + Home + Home + + + End + End + + + Left + 왼쪽 + + + Up + + + + Right + 오른쪽 + + + Down + 아래 + + + PgUp + PgUp + + + PgDown + PgDown + + + CapsLock + CapsLock + + + NumLock + NumLock + + + ScrollLock + ScrollLock + + + Menu + 메뉴 + + + Help + 도움말 + + + Back + 뒤로 + + + Forward + 앞으로 + + + Stop + 정지 + + + Refresh + 새로 고침 + + + Volume Down + 음량 감소 + + + Volume Mute + 음소거 + + + Volume Up + 음량 증가 + + + Bass Boost + 저음 강조 + + + Bass Up + 저음 증가 + + + Bass Down + 저음 감소 + + + Treble Up + 고음 증가 + + + Treble Down + 고음 감소 + + + Media Play + 미디어 재생 + + + Media Stop + 미디어 정지 + + + Media Previous + 미디어 이전 + + + Media Next + 미디어 다음 + + + Media Record + 미디어 녹음 + + + Media Pause + Media player pause button + 미디어 일시 정지 + + + Toggle Media Play/Pause + Media player button to toggle between playing and paused + 미디어 재생/일시 정지 + + + Home Page + 홈 페이지 + + + Favorites + 즐겨찾기 + + + Search + 검색 + + + Standby + 대기 모드 + + + Open URL + URL 열기 + + + Launch Mail + 메일 실행 + + + Launch Media + 미디어 실행 + + + Launch (0) + (0) 실행 + + + Launch (1) + (1) 실행 + + + Launch (2) + (2) 실행 + + + Launch (3) + (3) 실행 + + + Launch (4) + (4) 실행 + + + Launch (5) + (5) 실행 + + + Launch (6) + (6) 실행 + + + Launch (7) + (7) 실행 + + + Launch (8) + (8) 실행 + + + Launch (9) + (9) 실행 + + + Launch (A) + (A) 실행 + + + Launch (B) + (B) 실행 + + + Launch (C) + (C) 실행 + + + Launch (D) + (D) 실행 + + + Launch (E) + (E) 실행 + + + Launch (F) + (F) 실행 + + + Monitor Brightness Up + 모니터 밝기 증가 + + + Monitor Brightness Down + 모니터 밝기 감소 + + + Keyboard Light On/Off + 키보드 백라이트 켬/끔 + + + Keyboard Brightness Up + 키보드 밝기 증가 + + + Keyboard Brightness Down + 키보드 밝기 감소 + + + Power Off + 전원 끄기 + + + Wake Up + 깨어나기 + + + Eject + 꺼내기 + + + Screensaver + 화면 보호기 + + + WWW + WWW + + + Sleep + 대기 모드 + + + LightBulb + 조명등 + + + Shop + 쇼핑 + + + History + 과거 기록 + + + Add Favorite + 즐겨찾기에 추가 + + + Hot Links + 인기있는 링크 + + + Copy + 복사 + + + Cut + 잘라내기 + + + Paste + 붙여넣기 + + + Reload + 새로 고침 + + + Audio Forward + 오디오 빨리 감기 + + + Hot Links + Copy Link context menu item + 인기있는 링크 + + + Adjust Brightness + 밝기 조정 + + + Finance + 금융 + + + Community + 커뮤니티 + + + Audio Rewind + 오디오 되감기 + + + Back Forward + 뒤로 앞으로 + + + Application Left + 왼쪽 프로그램 + + + Application Right + 오른쪽 프로그램 + + + Book + + + + CD + CD + + + Calculator + 계산기 + + + Clear + 지우기 + + + Clear Grab + 선택 지우기 + + + Close + 닫기 + + + Copy + Copy context menu item + 복사 + + + Cut + Cut context menu item + 잘라내기 + + + Display + 디스플레이 + + + DOS + DOS + + + Documents + 문서 + + + Spreadsheet + 스프레드시트 + + + Browser + 브라우저 + + + Game + 게임 + + + Go + 이동 + + + iTouch + iTouch + + + Logoff + 로그오프 + + + Market + 마켓 + + + Meeting + 미팅 + + + Keyboard Menu + 키보드 메뉴 + + + Menu PB + 메뉴 PB + + + My Sites + 내 사이트 + + + News + 뉴스 + + + Home Office + 홈 오피스 + + + Option + 옵션 + + + Paste + Paste context menu item + 붙여넣기 + + + Phone + 전화 + + + Reply + 답장 + + + Reload + Reload context menu item + 새로 고침 + + + Rotate Windows + 창 회전 + + + Rotation PB + 회전 PB + + + Rotation KB + 회전 KB + + + Save + 저장 + + + Send + 보내기 + + + Spellchecker + 맞춤법 검사 + + + Split Screen + 화면 나누기 + + + Support + 지원 + + + Task Panel + 작업 패널 + + + Terminal + 터미널 + + + Tools + 도구 + + + Travel + 여행 + + + Video + 비디오 + + + Word Processor + 워드 프로세서 + + + XFer + 전송 + + + Zoom In + 확대 + + + Zoom Out + 축소 + + + Away + 자리 비움 + + + Messenger + 메신저 + + + WebCam + 웹캠 + + + Mail Forward + 메일 전달 + + + Pictures + 그림 + + + Music + 음악 + + + Battery + 배터리 + + + Bluetooth + 블루투스 + + + Wireless + 무선 + + + Ultra Wide Band + 광대역 + + + Audio Forward + Forward context menu item + 오디오 빨리 감기 + + + Audio Repeat + 오디오 반복 + + + Audio Random Play + 오디오 무순서 연주 + + + Subtitle + 자막 + + + Audio Cycle Track + 오디오 트랙 회전 + + + Time + 시간 + + + Select + 선택 + + + View + 보기 + + + Top Menu + 최상위 메뉴 + + + Suspend + 대기 모드 + + + Hibernate + 최대 절전 모드 + + + Print Screen + Print Screen + + + Page Up + Page Up + + + Page Down + Page Down + + + Caps Lock + Caps Lock + + + Num Lock + Num Lock + + + Number Lock + Number Lock + + + Scroll Lock + Scroll Lock + + + Insert + Insert + + + Delete + Delete + + + Escape + Escape + + + System Request + System Request + + + Yes + + + + No + 아니오 + + + Context1 + Context1 + + + Context2 + Context2 + + + Context3 + Context3 + + + Context4 + Context4 + + + Call + Button to start a call (note: a separate button is used to end the call) + 호출 + + + Hangup + Button to end a call (note: a separate button is used to start the call) + 끊기 + + + Toggle Call/Hangup + Button that will hang up if we're in call, or make a call if we're not. + 전화 걸기/끊기 + + + Flip + 뒤집기 + + + Voice Dial + Button to trigger voice dialing + 음성 다이얼 + + + Last Number Redial + Button to redial the last number called + 마지막 번호 재다이얼 + + + Camera Shutter + Button to trigger the camera shutter (take a picture) + 카메라 셔터 + + + Camera Focus + Button to focus the camera + 카메라 초점 + + + Kanji + 한자 + + + Muhenkan + 무변환 + + + Henkan + 변환 + + + Romaji + 로마자 + + + Hiragana + 히라가나 + + + Katakana + 가타가나 + + + Hiragana Katakana + 히라가나 가타가나 + + + Zenkaku + 전각 + + + Hankaku + 반각 + + + Zenkaku Hankaku + 전각 반각 + + + Touroku + + + + Massyo + + + + Kana Lock + 가나 Lock + + + Kana Shift + 가나 Shift + + + Eisu Shift + + + + Eisu toggle + + + + Code input + 코드 입력 + + + Multiple Candidate + 다중 후보 + + + Previous Candidate + 이전 후보 + + + Hangul + 한글 + + + Hangul Start + 한글 시작 + + + Hangul End + 한글 끝 + + + Hangul Hanja + 한글 한자 + + + Hangul Jamo + 한글 자모 + + + Hangul Romaja + 한글 로마자 + + + Hangul Jeonja + 한글 전자 + + + Hangul Banja + 한글 반자 + + + Hangul PreHanja + 한글 한자 시작 + + + Hangul PostHanja + 한글 한자 끝 + + + Hangul Special + 한글 특수 기호 + + + Ctrl + Ctrl + + + Shift + Shift + + + Alt + Alt + + + Meta + Meta + + + + + + + + + F%1 + F%1 + + + + QSlider + + Page left + 한 쪽 왼쪽으로 + + + Page up + 한 쪽 위로 + + + Position + 위치 + + + Page right + 한 쪽 오른쪽으로 + + + Page down + 한 쪽 아래로 + + + + QSocks5SocketEngine + + Connection to proxy refused + 프록시 연결이 거부됨 + + + Connection to proxy closed prematurely + 프록시 연결이 일찍 종료됨 + + + Proxy host not found + 프록시 호스트를 찾을 수 없음 + + + Connection to proxy timed out + 연결 시간 초과됨 + + + Proxy authentication failed + 프록시 인증 실패 + + + Proxy authentication failed: %1 + 프록시 인증 실패: %1 + + + SOCKS version 5 protocol error + SOCKS 버전 5 프로토콜 오류 + + + General SOCKSv5 server failure + 일반 SOCKSv5 서버 오류 + + + Connection not allowed by SOCKSv5 server + SOCKSv5 서버 연결이 허용되지 않음 + + + TTL expired + TTL 만료됨 + + + SOCKSv5 command not supported + SOCKSv5 명령을 지원하지 않음 + + + Address type not supported + 주소 형식을 지원하지 않음 + + + Unknown SOCKSv5 proxy error code 0x%1 + 알 수 없는 SOCKSv5 프록시 오류 코드 0x%1 + + + Network operation timed out + 네트워크 작업 시간 초과 + + + + QSoftKeyManager + + Ok + 확인 + + + Select + 선택 + + + Done + 완료 + + + Options + 옵션 + + + Cancel + 취소 + + + Exit + 끝내기 + + + + QSpinBox + + More + 더 보기 + + + Less + 덜 보기 + + + + QSql + + Delete + 삭제 + + + Delete this record? + 이 레코드를 삭제하시겠습니까? + + + Yes + + + + No + 아니오 + + + Insert + 삽입 + + + Update + 업데이트 + + + Save edits? + 편집을 저장하시겠습니까? + + + Cancel + 취소 + + + Confirm + 확인 + + + Cancel your edits? + 편집을 취소하시겠습니까? + + + + QSslSocket + + No error + 오류 없음 + + + The issuer certificate could not be found + 발급자 인증서를 찾을 수 없음 + + + The certificate signature could not be decrypted + 인증서 서명을 복호화할 수 없음 + + + The public key in the certificate could not be read + 인증서의 공개 키를 읽을 수 없음 + + + The signature of the certificate is invalid + 인증서의 서명이 올바르지 않음 + + + The certificate is not yet valid + 인증서가 아직 유효하지 않음 + + + The certificate has expired + 인증서가 만료됨 + + + The certificate's notBefore field contains an invalid time + 인증서의 notBefore 필드에 올바르지 않은 시간이 들어 있음 + + + The certificate's notAfter field contains an invalid time + 인증서의 notAfter 필드에 올바르지 않은 시간이 들어 있음 + + + The certificate is self-signed, and untrusted + 인증서가 자가 서명되었고 믿을 수 없음 + + + The root certificate of the certificate chain is self-signed, and untrusted + 인증서 체인의 루트 인증서가 자가 서명되었고 믿을 수 없음 + + + The issuer certificate of a locally looked up certificate could not be found + 로컬에서 찾은 인증서의 발급자 인증서를 찾을 수 없음 + + + No certificates could be verified + 아무 인증서도 검증할 수 없음 + + + One of the CA certificates is invalid + CA 인증서 중 하나 이상이 올바르지 않음 + + + The basicConstraints path length parameter has been exceeded + basicConstraints 경로 길이 인자가 초과됨 + + + The supplied certificate is unsuitable for this purpose + 지정한 인증서를 이 목적으로는 사용할 수 없음 + + + The root CA certificate is not trusted for this purpose + 루트 CA 인증서를 이 목적으로 신뢰할 수 없음 + + + The root CA certificate is marked to reject the specified purpose + 루트 CA 인증서는 이 목적으로 사용이 거부됨 + + + The current candidate issuer certificate was rejected because its subject name did not match the issuer name of the current certificate + 현재 인증서의 발급자 이름과 상위 인증서의 이름이 일치하지 않아서 현재 후보 발급자 인증서가 거부되었습니다 + + + The current candidate issuer certificate was rejected because its issuer name and serial number was present and did not match the authority key identifier of the current certificate + 현재 인증서의 인증자 키 식별자와 발급자 이름 및 시리얼 번호가 일치하지 않아서 현재 후보 발급자 인증서가 거부되었습니다 + + + The peer did not present any certificate + 동료 측이 인증서를 제시하지 않았음 + + + The host name did not match any of the valid hosts for this certificate + 호스트 이름이 이 인증서에서 지정한 유효한 호스트 중 아무 것도 일치하지 않음 + + + Unknown error + 알 수 없는 오류 + + + Error creating SSL context (%1) + SSL 컨텍스트를 만드는 중 오류 발생(%1) + + + Invalid or empty cipher list (%1) + 잘못되거나 비어 있는 암호화 키 목록 (%1) + + + Cannot provide a certificate with no key, %1 + 키가 없는 인증서를 제공할 수 없음, %1 + + + Error loading local certificate, %1 + 로컬 인증서를 불러올 수 없음, %1 + + + Error loading private key, %1 + 개인 키를 불러올 수 없음, %1 + + + Private key does not certify public key, %1 + 개인 키가 공개 키를 인증하지 않음, %1 + + + Error creating SSL session, %1 + SSL 세션을 만드는 중 오류 발생, %1 + + + Error creating SSL session: %1 + SSL 세션을 만드는 중 오류 발생: %1 + + + Unable to write data: %1 + 데이터를 쓸 수 없음: %1 + + + Unable to decrypt data: %1 + 데이터를 복호화할 수 없음: %1 + + + Error while reading: %1 + 읽는 중 오류 발생: %1 + + + Error during SSL handshake: %1 + SSL 악수 중 오류 발생: %1 + + + + QStateMachine + + Missing initial state in compound state '%1' + 복합 상태 '%1'의 초기 상태가 없음 + + + Missing default state in history state '%1' + 과거 기록 상태 '%1'에 기본 상태가 없음 + + + No common ancestor for targets and source of transition from state '%1' + 상태 '%1'에서 전환되는 원본과 대상에 공통된 조상이 없음 + + + Unknown error + 알 수 없는 오류 + + + + QSystemSemaphore + + %1: permission denied + QSystemSemaphore + %1: 권한이 거부됨 + + + %1: already exists + QSystemSemaphore + %1: 이미 존재함 + + + %1: does not exist + QSystemSemaphore + %1: 존재하지 않음 + + + %1: out of resources + QSystemSemaphore + %1: 자원 부족 + + + %1: unknown error %2 + QSystemSemaphore + %1: 알 수 없는 오류 %2 + + + %1: permission denied + %1: 권한이 거부됨 + + + %1: already exists + %1: 이미 존재함 + + + %1: does not exist + %1: 존재하지 않음 + + + %1: out of resources + %1: 자원 부족 + + + %1: unknown error %2 + %1: 알 수 없는 오류 %2 + + + + QTDSDriver + + Unable to open connection + 연결을 열 수 없음 + + + Unable to use database + 데이터베이스를 사용할 수 없음 + + + + QTabBar + + Scroll Left + 왼쪽으로 스크롤 + + + Scroll Right + 오른쪽으로 스크롤 + + + + QTcpServer + + Operation on socket is not supported + 소켓 작업을 지원하지 않음 + + + + QTextControl + + &Undo + 실행 취소(&U) + + + &Redo + 다시 실행(&R) + + + Cu&t + 잘라내기(&T) + + + &Copy + 복사(&C) + + + Copy &Link Location + 링크 주소 복사(&L) + + + &Paste + 붙여넣기(&P) + + + Delete + 삭제 + + + Select All + 모두 선택 + + + + QToolButton + + Press + 누름 + + + Open + 열기 + + + + QUdpSocket + + This platform does not support IPv6 + 이 플랫폼은 IPv6을 지원하지 않습니다 + + + + QUndoGroup + + Undo + 실행 취소 + + + Redo + 다시 실행 + + + + QUndoModel + + <empty> + <비어 있음> + + + + QUndoStack + + Undo + 실행 취소 + + + Redo + 다시 실행 + + + + QUnicodeControlCharacterMenu + + LRM Left-to-right mark + LRM 왼쪽에서 오른쪽 기호 + + + RLM Right-to-left mark + RLM 오른쪽에서 왼쪽 기호 + + + ZWJ Zero width joiner + ZWJ 폭이 0인 결합자 + + + ZWNJ Zero width non-joiner + ZWNJ 폭이 0인 비결합자 + + + ZWSP Zero width space + ZWSP 폭이 0인 공백 + + + LRE Start of left-to-right embedding + LRE 왼쪽에서 오른쪽 임베딩 시작 + + + RLE Start of right-to-left embedding + RLE 오른쪽에서 왼쪽 임베딩 시작 + + + LRO Start of left-to-right override + LRO 왼쪽에서 오른쪽 재정의 시작 + + + RLO Start of right-to-left override + RLO 오른쪽에서 왼쪽 재정의 시작 + + + PDF Pop directional formatting + PDF Pop 방향 포매팅 + + + Insert Unicode control character + 유니코드 제어 문자 삽입 + + + + QWebFrame + + Request cancelled + 요청 취소됨 + + + Request blocked + 요청 거부됨 + + + Cannot show URL + URL을 표시할 수 없음 + + + Frame load interrupted by policy change + 정책 변경으로 프레임 불러오기 취소됨 + + + Cannot show mimetype + MIME 형식을 표시할 수 없음 + + + File does not exist + 파일이 존재하지 않음 + + + + QWebPage + + Redirection limit reached + 넘겨주기 한계에 도달함 + + + Bad HTTP request + 잘못된 HTTP 요청 + + + %n file(s) + number of chosen file + + 파일 %n개 + + + + Submit + default label for Submit buttons in forms on web pages + 보내기 + + + Reset + 초기화 + + + This is a searchable index. Enter search keywords: + text that appears at the start of nearly-obsolete web pages in the form of a 'searchable index' + 검색 가능한 인덱스입니다. 검색할 단어를 입력하십시오: + + + Choose File + title for file button used in HTML forms + 파일 선택 + + + No file selected + text to display in file button used in HTML forms when no file is selected + 파일이 선택되지 않음 + + + Open in New Window + Open in New Window context menu item + 새 창으로 열기 + + + Save Link... + Download Linked File context menu item + 링크 저장... + + + Copy Link + Copy Link context menu item + 링크 복사 + + + Open Image + Open Image in New Window context menu item + 그림 열기 + + + Save Image + Download Image context menu item + 그림 저장 + + + Copy Image + Copy Link context menu item + 그림 복사 + + + Open Frame + Open Frame in New Window context menu item + 프레임 열기 + + + Copy + Copy context menu item + 복사 + + + Go Back + Back context menu item + 뒤로 가기 + + + Go Forward + Forward context menu item + 앞으로 가기 + + + Stop + 정지 + + + Reload + Reload context menu item + 새로 고침 + + + Cut + Cut context menu item + 잘라내기 + + + Paste + Paste context menu item + 붙여넣기 + + + No Guesses Found + No Guesses Found context menu item + 추천 단어 없음 + + + Ignore + 무시 + + + Add To Dictionary + Learn Spelling context menu item + 사전에 추가하기 + + + Search The Web + Search The Web context menu item + 웹 검색하기 + + + Look Up In Dictionary + Look Up in Dictionary context menu item + 사전 찾기 + + + Open Link + Open Link context menu item + 링크 열기 + + + Spelling + Spelling and Grammar context sub-menu item + 맞춤법 + + + Show Spelling and Grammar + menu item title + 맞춤법 오류 보이기 + + + Hide Spelling and Grammar + menu item title + 맞춤법 오류 숨기기 + + + Check Spelling + Check spelling context menu item + 맞춤법 검사 + + + Check Spelling While Typing + Check spelling while typing context menu item + 입력하는 동안 맞춤법 검사 + + + Check Grammar With Spelling + Check grammar with spelling context menu item + 문법 오류 검사하기 + + + Fonts + Font context sub-menu item + 글꼴 + + + Bold + 굵게 + + + Italic + 이탤릭 + + + Underline + Underline context menu item + 밑줄 + + + Outline + Outline context menu item + 외곽선 + + + Direction + Writing direction context sub-menu item + 방향 + + + Text Direction + Writing direction context sub-menu item + 텍스트 방향 + + + Default + Default writing direction context menu item + 기본 + + + Left to Right + Left to Right context menu item + 왼쪽에서 오른쪽 + + + Right to Left + 오른쪽에서 왼쪽 + + + Inspect + Inspect Element context menu item + 들여다 보기 + + + No recent searches + Label for only item in menu that appears when clicking on the search field image, when no searches have been performed + 최근 검색 없음 + + + Recent searches + label for first item in the menu that appears when clicking on the search field image, used as embedded menu title + 최근 검색 + + + Clear recent searches + menu item in Recent Searches menu that empties menu's contents + 최근 검색 지우기 + + + Missing Plug-in + Label text to be used when a plug-in is missing + 플러그인이 존재하지 않음 + + + Unknown + 알 수 없음 + + + %1 (%2x%3 pixels) + Title string for images + %1 (%2x%3 픽셀) + + + Loading... + Media controller status message when the media is loading + 불러오는 중... + + + Live Broadcast + Media controller status message when watching a live broadcast + 라이브 방송 + + + Audio Element + Media controller element + 오디오 구성 요소 + + + Video Element + Media controller element + 비디오 구성 요소 + + + Mute Button + Media controller element + 음소거 단추 + + + Unmute Button + Media controller element + 음소거 해제 단추 + + + Play Button + Media controller element + 재생 단추 + + + Pause Button + Media controller element + 일시 정지 단추 + + + Slider + 슬라이더 + + + Submit + Submit (input element) alt text for <input> elements with no alt, title, or value + 보내기 + + + Reset + default label for Reset buttons in forms on web pages + 초기화 + + + Stop + Stop context menu item + 정지 + + + Ignore + Ignore Spelling context menu item + 무시 + + + Ignore + Ignore Grammar context menu item + 무시 + + + Bold + Bold context menu item + 굵게 + + + Italic + Italic context menu item + 이탤릭 + + + Text Direction + Text direction context sub-menu item + 텍스트 방향 + + + Right to Left + Right to Left context menu item + 오른쪽에서 왼쪽 + + + Unknown + Unknown filesize FTP directory listing item + 알 수 없음 + + + Slider + Media controller element + 슬라이더 + + + Slider Thumb + Media controller element + 슬라이더 핸들 + + + Rewind Button + Media controller element + 되감기 단추 + + + Return to Real-time Button + Media controller element + 실시간으로 복귀 단추 + + + Elapsed Time + Media controller element + 경과 시간 + + + Remaining Time + Media controller element + 남은 시간 + + + Status Display + Media controller element + 상태 디스플레이 + + + Fullscreen Button + Media controller element + 전체 화면 단추 + + + Seek Forward Button + Media controller element + 앞으로 이동 단추 + + + Seek Back Button + Media controller element + 뒤로 이동 단추 + + + Audio element playback controls and status display + Media controller element + 오디오 구성 요소 재생 제어 및 상태 표시 + + + Video element playback controls and status display + Media controller element + 비디오 구성 요소 제어 및 상태 표시 + + + Mute audio tracks + Media controller element + 오디오 트랙 음소거 + + + Unmute audio tracks + Media controller element + 오디오 트랙 음소거 해제 + + + Begin playback + Media controller element + 재생 시작 + + + Pause playback + Media controller element + 재생 일시 정지 + + + Movie time scrubber + Media controller element + 동영상 시간 표시기 + + + Movie time scrubber thumb + Media controller element + 동영상 시간 표시기 핸들 + + + Rewind movie + Media controller element + 동영상 되감기 + + + Return streaming movie to real-time + Media controller element + 스트리밍 동영상 실시간으로 전환 + + + Current movie time + Media controller element + 현재 동영상 시간 + + + Remaining movie time + Media controller element + 남은 동영상 시간 + + + Current movie status + Media controller element + 현재 동영상 상태 + + + Play movie in full-screen mode + Media controller element + 전체 화면으로 동영상 재생 + + + Seek quickly back + Media controller element + 뒤로 빨리 이동 + + + Seek quickly forward + Media controller element + 앞으로 빨리 이동 + + + Indefinite time + Media time description + 무한한 시간 + + + %1 days %2 hours %3 minutes %4 seconds + Media time description + %1일 %2시간 %3분 %4초 + + + %1 hours %2 minutes %3 seconds + Media time description + %1시간 %2분 %3초 + + + %1 minutes %2 seconds + Media time description + %1분 %2초 + + + %1 seconds + Media time description + %1초 + + + Scroll here + 여기로 스크롤 + + + Left edge + 왼쪽 경계 + + + Top + 맨 위 + + + Right edge + 오른쪽 경계 + + + Bottom + 맨 아래 + + + Page left + 왼쪽 페이지 + + + Page up + 위쪽 페이지 + + + Page right + 오른쪽 페이지 + + + Page down + 아래쪽 페이지 + + + Scroll left + 왼쪽으로 스크롤 + + + Scroll up + 위로 스크롤 + + + Scroll right + 오른쪽으로 스크롤 + + + Scroll down + 아래로 스크롤 + + + JavaScript Alert - %1 + 자바스크립트 알림 - %1 + + + JavaScript Confirm - %1 + 자바스크립트 확인 - %1 + + + JavaScript Prompt - %1 + 자바스크립트 질문 - %1 + + + JavaScript Problem - %1 + 자바스크립트 오류 - %1 + + + The script on this page appears to have a problem. Do you want to stop the script? + 이 페이지에 있는 스크립트에 문제가 있는 것 같습니다. 스크립트 실행을 중단하시겠습니까? + + + Move the cursor to the next character + 다음 글자로 커서 이동 + + + Move the cursor to the previous character + 이전 글자로 커서 이동 + + + Move the cursor to the next word + 다음 단어로 커서 이동 + + + Move the cursor to the previous word + 이전 단어로 커서 이동 + + + Move the cursor to the next line + 다음 줄로 커서 이동 + + + Move the cursor to the previous line + 앞 줄로 커서 이동 + + + Move the cursor to the start of the line + 줄 처음으로 커서 이동 + + + Move the cursor to the end of the line + 줄 끝으로 커서 이동 + + + Move the cursor to the start of the block + 블록 시작으로 커서 이동 + + + Move the cursor to the end of the block + 블록 끝으로 커서 이동 + + + Move the cursor to the start of the document + 문서 시작으로 커서 이동 + + + Move the cursor to the end of the document + 문서 끝으로 커서 이동 + + + Select all + 모두 선택 + + + Select to the next character + 다음 글자 선택 + + + Select to the previous character + 이전 글자 선택 + + + Select to the next word + 다음 단어 선택 + + + Select to the previous word + 이전 단어 선택 + + + Select to the next line + 다음 줄 선택 + + + Select to the previous line + 앞 줄 선택 + + + Select to the start of the line + 줄 처음까지 선택 + + + Select to the end of the line + 줄 끝까지 선택 + + + Select to the start of the block + 블록 처음까지 선택 + + + Select to the end of the block + 블록 끝까지 선택 + + + Select to the start of the document + 문서 처음까지 선택 + + + Select to the end of the document + 문서 끝까지 선택 + + + Delete to the start of the word + 단어 처음까지 삭제 + + + Delete to the end of the word + 단어 끝까지 삭제 + + + Insert a new paragraph + 새 문단 삽입 + + + Insert a new line + 새 줄 삽입 + + + Paste and Match Style + 붙여넣고 스타일 일치시키기 + + + Remove formatting + 서식 삭제 + + + Strikethrough + 취소선 + + + Subscript + 아래 첨자 + + + Superscript + 위 첨자 + + + Insert Bulleted List + 불릿 목록 삽입하기 + + + Insert Numbered List + 번호 목록 삽입하기 + + + Indent + 들여쓰기 + + + Outdent + 내어쓰기 + + + Center + 가운데 + + + Justify + 맞춤 + + + Align Left + 왼쪽으로 정렬 + + + Align Right + 오른쪽으로 정렬 + + + Web Inspector - %2 + 웹 들여다보기 - %2 + + + + QWhatsThisAction + + What's This? + 이것에 대한 설명 + + + + QWidget + + * + * + + + + QWizard + + Go Back + 뒤로 가기 + + + < &Back + < 뒤로(&B) + + + Continue + 계속 + + + &Next + 다음(&N) + + + &Next > + 다음 (&N) > + + + Commit + 커밋 + + + Done + 완료 + + + &Finish + 완료(&F) + + + Cancel + 취소 + + + Help + 도움말 + + + &Help + 도움말(&H) + + + + QWorkspace + + Close + 닫기 + + + Minimize + 최소화 + + + Restore Down + 복원 + + + &Restore + 복원(&R) + + + &Move + 이동(&M) + + + &Size + 크기(&S) + + + Mi&nimize + 최소화(&N) + + + Ma&ximize + 최대화(&N) + + + &Close + 닫기(&C) + + + Stay on &Top + 항상 위(&T) + + + Sh&ade + 말아 올리기(&A) + + + %1 - [%2] + %1 - [%2] + + + &Unshade + 풀어 내리기(&U) + + + + QXml + + no error occurred + 오류 없음 + + + error triggered by consumer + 사용자가 오류를 발생시킴 + + + unexpected end of file + 예상하지 못한 파일의 끝 + + + more than one document type definition + 하나 이상의 문서 형식 정의가 있음 + + + error occurred while parsing element + 원소를 처리하는 중 오류 발생 + + + tag mismatch + 태그가 일치하지 않음 + + + error occurred while parsing content + 내용을 처리하는 중 오류 발생 + + + unexpected character + 예상하지 못한 글자 + + + invalid name for processing instruction + 잘못된 이름이나 처리 방법 + + + version expected while reading the XML declaration + XML 선언을 읽는 중 버전이 필요함 + + + wrong value for standalone declaration + 독립 문서 선언의 값이 잘못됨 + + + encoding declaration or standalone declaration expected while reading the XML declaration + XML 선언을 읽는 중 인코딩이나 독립 문서 선언이 필요함 + + + standalone declaration expected while reading the XML declaration + XML 선언을 읽는 중 독립 문서 선언이 필요함 + + + error occurred while parsing document type definition + 문서 형식 정의를 처리하는 중 오류 발생 + + + letter is expected + 글자가 필요함 + + + error occurred while parsing comment + 주석을 처리하는 중 오류 발생 + + + error occurred while parsing reference + 참조를 처리하는 중 오류 발생 + + + internal general entity reference not allowed in DTD + DTD에서 내부 일반 엔티티 참조를 사용할 수 없음 + + + external parsed general entity reference not allowed in attribute value + 속성 값에는 외부에서 처리한 일반 엔티티 참조를 사용할 수 없음 + + + external parsed general entity reference not allowed in DTD + DTD에서 외부에서 처리한 일반 엔티티 참조를 사용할 수 없음 + + + unparsed entity reference in wrong context + 잘못된 컨텍스트에 처리되지 않은 엔티티 참조가 있음 + + + recursive entities + 재귀적 엔티티 + + + error in the text declaration of an external entity + 외부 엔티티 텍스트 선언에 오류가 있음 + + + + QXmlPatternistCLI + + Warning in %1, at line %2, column %3: %4 + %1의 %2번째 줄 %3번째 글자에서 경고 발생: %4 + + + Warning in %1: %2 + %1에서 경고 발생: %2 + + + Unknown location + 알 수 없는 위치 + + + Error %1 in %2, at line %3, column %4: %5 + %2의 %3번째 줄 %4번째 글자에서 오류 %1 발생: %5 + + + Error %1 in %2: %3 + %2에서 오류 %1 발생: %3 + + + + QXmlStream + + Extra content at end of document. + 문서의 끝에 내용이 더 있습니다. + + + Invalid entity value. + 엔티티 값이 잘못되었습니다. + + + Invalid XML character. + XML 글자가 잘못되었습니다. + + + Sequence ']]>' not allowed in content. + 내용에 문자열 ']]>'가 올 수 없습니다. + + + Encountered incorrectly encoded content. + 잘못 인코딩된 내용을 발견하였습니다. + + + Namespace prefix '%1' not declared + 네임스페이스 접두사 '%1'이(가) 선언되지 않았음 + + + Illegal namespace declaration. + 네임스페이스 선언이 잘못되었습니다. + + + Attribute redefined. + 속성이 재정의되었습니다. + + + Unexpected character '%1' in public id literal. + 공개 ID 리터럴에 예상하지 못한 문자 '%1'이(가) 있습니다. + + + Invalid XML version string. + XML 버전 문자열이 잘못되었습니다. + + + Unsupported XML version. + 지원하지 않는 XML 버전입니다. + + + The standalone pseudo attribute must appear after the encoding. + standalone 의사 속성은 인코딩 다음에 와야 합니다. + + + %1 is an invalid encoding name. + 인코딩 이름 %1이(가) 잘못되었습니다. + + + Encoding %1 is unsupported + 인코딩 %1은(는) 지원되지 않습니다 + + + Standalone accepts only yes or no. + Standalone에는 yes나 no만 지정할 수 있습니다. + + + Invalid attribute in XML declaration. + XML 선언에서 속성이 잘못되었습니다. + + + Premature end of document. + 문서가 완전하지 못하게 끝났습니다. + + + Invalid document. + 문서가 잘못되었습니다. + + + Expected + 다음을 예상했지만 + + + , but got ' + , 돌아온 것은 ' + + + Unexpected ' + 예상하지 못한 ' + + + Expected character data. + 예상하지 못한 문자열 데이터입니다. + + + Recursive entity detected. + 재귀적 엔티티가 감지되었습니다. + + + Start tag expected. + 시작 태그가 필요합니다. + + + NDATA in parameter entity declaration. + 인자 엔티티 선언에 NDATA가 있습니다. + + + XML declaration not at start of document. + XML 선언이 문서 시작에 없습니다. + + + %1 is an invalid processing instruction name. + %1은(는) 잘못된 처리 방법 이름입니다. + + + Invalid processing instruction name. + 잘못된 처리 방법 이름입니다. + + + %1 is an invalid PUBLIC identifier. + %1은(는) 잘못된 PUBLIC 식별자입니다. + + + Invalid XML name. + XML 이름이 잘못되었습니다. + + + Opening and ending tag mismatch. + 여는 태그와 닫는 태그가 일치하지 않습니다. + + + Entity '%1' not declared. + 엔티티 '%1'이(가) 선언되지 않았습니다. + + + Reference to unparsed entity '%1'. + 처리되지 않은 엔티티 '%1'을(를) 참고합니다. + + + Reference to external entity '%1' in attribute value. + 속성 값에서 외부 엔티티 '%1'을(를) 참조하고 있습니다. + + + Invalid character reference. + 잘못된 문자 참조입니다. + + + + QtXmlPatterns + + %1 is an unsupported encoding. + 인코딩 %1은(는) 지원하지 않습니다. + + + %1 contains octets which are disallowed in the requested encoding %2. + %1은(는) 요청한 인코딩 %2에서 사용할 수 없는 바이트 배열을 포함합니다. + + + The codepoint %1, occurring in %2 using encoding %3, is an invalid XML character. + 인코딩 %3을(를) 사용하며 %2에 있는 코드포인트 %1은(는) 올바르지 않은 XML 문자입니다. + + + Network timeout. + 네트워크 시간 초과됨. + + + Element %1 can't be serialized because it appears outside the document element. + 원소 %1이(가) 문서 밖에 나오므로 시리얼화할 수 없습니다. + + + Attribute %1 can't be serialized because it appears at the top level. + 속성 %1이(가) 최상위 단계에 나타나므로 시리얼화할 수 없습니다. + + + Year %1 is invalid because it begins with %2. + %1년은 %2(으)로 시작하므로 올바르지 않습니다. + + + Day %1 is outside the range %2..%3. + 날짜 %1은(는) %2..%3 범위 밖에 있습니다. + + + Month %1 is outside the range %2..%3. + 달 %1은(는) 범위 %2..%3 밖에 있습니다. + + + Overflow: Can't represent date %1. + 넘침: 날짜 %1을(를) 표시할 수 없습니다. + + + Day %1 is invalid for month %2. + %2월에는 %1일이 없습니다. + + + Time 24:%1:%2.%3 is invalid. Hour is 24, but minutes, seconds, and milliseconds are not all 0; + 24시간제 시간 24:%1:%2.%3이(가) 올바르지 않습니다. 시간은 24이나 분, 초, 밀리초가 모두 0 이상입니다; + + + Time %1:%2:%3.%4 is invalid. + 시간 %1:%2:%3.%4이(가) 올바르지 않습니다. + + + Overflow: Date can't be represented. + 넘침: 날짜를 표시할 수 없습니다. + + + At least one component must be present. + 최소한 하나의 구성 요소가 필요합니다. + + + At least one time component must appear after the %1-delimiter. + 구분자 %1 이후에 최소 하나의 시간 구성 요소가 나와야 합니다. + + + %1 is not a valid value of type %2. + %1은(는) 올바른 %2 형식의 값이 아닙니다. + + + When casting to %1 from %2, the source value cannot be %3. + %1에서 %2(으)로 변환할 때 원본 값이 %3일 수 없습니다. + + + Integer division (%1) by zero (%2) is undefined. + 0(%2)으로 나누는 정수 나눗셈(%1)은 정의되지 않았습니다. + + + Division (%1) by zero (%2) is undefined. + 0(%2)으로 나누는 나눗셈(%1)은 정의되지 않았습니다. + + + Modulus division (%1) by zero (%2) is undefined. + 0(%2)으로 나눈 나머지(%1)는 정의되지 않았습니다. + + + Dividing a value of type %1 by %2 (not-a-number) is not allowed. + %1 형식의 값을 %2(숫자가 아님)(으)로 나누는 것은 허용되지 않습니다. + + + Dividing a value of type %1 by %2 or %3 (plus or minus zero) is not allowed. + %1 형식의 값을 %2나 %3(+0/-0)(으)로 나누는 것은 허용되지 않습니다. + + + Multiplication of a value of type %1 by %2 or %3 (plus or minus infinity) is not allowed. + %1 형식의 값을 %2나 %3(양이나 음의 무한대)(으)로 곱하는 것은 허용되지 않습니다. + + + A value of type %1 cannot have an Effective Boolean Value. + %1 형식의 값은 유효한 참/거짓을 가질 수 없습니다. + + + Effective Boolean Value cannot be calculated for a sequence containing two or more atomic values. + 유효한 참/거짓 값은 두 개 이상의 원자적인 값을 포함하는 배열과 함께 계산될 수 없습니다. + + + Value %1 of type %2 exceeds maximum (%3). + %2 형식의 값 %1이(가) 최댓값 %3보다 큽니다. + + + Value %1 of type %2 is below minimum (%3). + %2 형식의 값 %1이(가) 최솟값 %3보다 작습니다. + + + A value of type %1 must contain an even number of digits. The value %2 does not. + %1 형식의 값은 짝수 자리수만 포함할 수 있으나, 값 %2은(는) 그렇지 않습니다. + + + %1 is not valid as a value of type %2. + %1은(는) 올바른 %2 형식의 값이 아닙니다. + + + Ambiguous rule match. + 모호한 규칙 일치. + + + Operator %1 cannot be used on type %2. + 연산자 %1은(는) 형식 %2에 사용할 수 없습니다. + + + Operator %1 cannot be used on atomic values of type %2 and %3. + 연산자 %1은(는) %2, %3 형식의 원자적인 값에 사용할 수 없습니다. + + + The namespace URI in the name for a computed attribute cannot be %1. + 계산된 속성 이름의 네임스페이스 URL는 %1일 수 없습니다. + + + The name for a computed attribute cannot have the namespace URI %1 with the local name %2. + 계산된 속성 이름의 네임스페이스 URL는 %1, 로컬 이름은 %2일 수 없습니다. + + + Type error in cast, expected %1, received %2. + 변환 중 형식 오류, %1을(를) 예상했지만 %2을(를) 받음. + + + When casting to %1 or types derived from it, the source value must be of the same type, or it must be a string literal. Type %2 is not allowed. + %1 및 파생 형식으로 변환하려면 원본 값은 같은 형식이거나 문자열 리터럴이어야 합니다. %2 형식은 허용되지 않습니다. + + + A comment cannot contain %1 + 주석에는 %1을(를) 포함할 수 없음 + + + A comment cannot end with a %1. + 주석은 %1(으)로 끝날 수 없습니다. + + + In a namespace constructor, the value for a namespace cannot be an empty string. + 네임스페이스 생성자에서 네임스페이스의 값은 빈 문자열일 수 없습니다. + + + The prefix must be a valid %1, which %2 is not. + 접두사는 올바른 %1이어야 하지만, %2은(는) 그렇지 않습니다. + + + The prefix %1 cannot be bound. + 접두사 %1이(가) 바인딩될 수 없습니다. + + + Only the prefix %1 can be bound to %2 and vice versa. + 접두사 %1만 %2에 바인딩할 수 있으며, 그 역도 마찬가지입니다. + + + An attribute node cannot be a child of a document node. Therefore, the attribute %1 is out of place. + 속성 노드는 문서 노드의 자식이 될 수 없습니다. 따라서 속성 %1의 위치가 잘못되었습니다. + + + A library module cannot be evaluated directly. It must be imported from a main module. + 라이브러리 모듈은 직접적으로 실행될 수 없으며, 주 모듈에서 가져와야 합니다. + + + No template by name %1 exists. + 이름이 %1인 템플릿이 없습니다. + + + A value of type %1 cannot be a predicate. A predicate must have either a numeric type or an Effective Boolean Value type. + %1 형식의 값은 술어가 될 수 없습니다. 술어는 숫자 형식이나 유효한 참/거짓 형식의 값을 가져야 합니다. + + + A positional predicate must evaluate to a single numeric value. + 위치가 정해진 술어는 유일한 숫자 값으로 해석되어야 합니다. + + + The target name in a processing instruction cannot be %1 in any combination of upper and lower case. Therefore, %2 is invalid. + 처리 과정의 대상 이름은 %1을(를) 모두 대문자나 소문자로 써야 하므로, %2은(는) 올바르지 않습니다. + + + %1 is not a valid target name in a processing instruction. It must be a %2 value, e.g. %3. + %1은(는) 올바른 처리 방법 대상 이름이 아닙니다. %3와(과) 같은 %2 값이어야 합니다. + + + The last step in a path must contain either nodes or atomic values. It cannot be a mixture between the two. + 경로의 마지막 단계는 노드나 원자적 값만 포함할 수 있으며, 둘을 같이 사용할 수 없습니다. + + + The data of a processing instruction cannot contain the string %1 + 처리 과정의 데이터는 문자열 %1을(를) 포함할 수 없습니다 + + + No namespace binding exists for the prefix %1 + 접두사 %1의 네임스페이스 바인딩이 존재하지 않습니다 + + + No namespace binding exists for the prefix %1 in %2 + %2의 접두사 %1의 네임스페이스 바인딩이 존재하지 않습니다 + + + %1 is an invalid %2 + %1은(는) 올바르지 않은 %2입니다 + + + The parameter %1 is passed, but no corresponding %2 exists. + 인자 %1이(가) 전달되었으나 대응하는 %2이(가) 없습니다. + + + The parameter %1 is required, but no corresponding %2 is supplied. + 인자 %1이(가) 필요하나, 해당하는 %2이(가) 없습니다. + + + %1 takes at most %n argument(s). %2 is therefore invalid. + + %1은(는) 최대 %n개의 인자를 받아들이므로, %2은(는) 올바르지 않습니다. + + + + %1 requires at least %n argument(s). %2 is therefore invalid. + + %1은(는) 최소 %n개의 인자를 받아들이므로, %2은(는) 올바르지 않습니다. + + + + The first argument to %1 cannot be of type %2. It must be a numeric type, xs:yearMonthDuration or xs:dayTimeDuration. + %1의 첫 번째 인자는 %2 형식일 수 없습니다. 숫자나 xs:yearMonthDuration, xs:dayTimeDuration 형식이어야 합니다. + + + The first argument to %1 cannot be of type %2. It must be of type %3, %4, or %5. + %1의 첫 번째 인자는 %2 형식일 수 없습니다. %3, %4, %5 형식이어야 합니다. + + + The second argument to %1 cannot be of type %2. It must be of type %3, %4, or %5. + %1의 두 번째 인자는 %2 형식일 수 없습니다. %3, %4, %5 형식이어야 합니다. + + + %1 is not a valid XML 1.0 character. + %1은(는) 올바르지 않은 XML 1.0 글자입니다. + + + The root node of the second argument to function %1 must be a document node. %2 is not a document node. + 함수 %1의 두 번째 인자의 루트 노드는 문서 노드여야 합니다. %2은(는) 문서 노드가 아닙니다. + + + If both values have zone offsets, they must have the same zone offset. %1 and %2 are not the same. + 두 값이 모두 지역 오프셋을 가지고 있다면 같아야 합니다. %1와(과) %2은(는) 같지 않습니다. + + + %1 was called. + %1이(가) 호출되었습니다. + + + %1 must be followed by %2 or %3, not at the end of the replacement string. + %1은(는) %2(이)나 %3 뒤에 와야 하며, 바꿀 문자열 뒤에 올 수 없습니다. + + + In the replacement string, %1 must be followed by at least one digit when not escaped. + 바꿀 문자열이 이스케이핑되지 않았다면 %1 뒤에 숫자가 최소 하나는 와야 합니다. + + + In the replacement string, %1 can only be used to escape itself or %2, not %3 + 바꿀 문자열에서 %1은(는) 자기 자신이나 %2을(를) 이스케이핑하는 데 사용해야 하며, %3에는 사용할 수 없습니다 + + + %1 matches newline characters + %1은(는) 새 줄 문자에 일치합니다 + + + %1 and %2 match the start and end of a line. + %1와(과) %2은(는) 각각 줄의 시작과 끝에 일치합니다. + + + Matches are case insensitive + 대소문자를 구분하여 일치시킵니다 + + + Whitespace characters are removed, except when they appear in character classes + 문자 클래스에 나타나지 않으면 공백 문자는 삭제됩니다 + + + %1 is an invalid regular expression pattern: %2 + %1은(는) 올바른 정규 표현식 패턴이 아닙니다: %2 + + + %1 is an invalid flag for regular expressions. Valid flags are: + %1은(는) 올바르지 않은 정규 표현식 플래그입니다. 올바른 플래그는 다음과 같습니다: + + + If the first argument is the empty sequence or a zero-length string (no namespace), a prefix cannot be specified. Prefix %1 was specified. + 첫 번째 인자가 빈 시퀀스나 빈 문자열(네임스페이스 없음)인 경우, 접두사를 지정할 수 없습니다. 접두사 %1이(가) 지정되었습니다. + + + It will not be possible to retrieve %1. + %1을(를) 가져올 수 없습니다. + + + The default collection is undefined + 기본 조건이 정의되지 않았음 + + + %1 cannot be retrieved + %1을(를) 가져올 수 없음 + + + The normalization form %1 is unsupported. The supported forms are %2, %3, %4, and %5, and none, i.e. the empty string (no normalization). + 정규화 형식 %1은(는) 지원하지 않습니다. 지원하는 형식은 %2, %3, %4, %5이며, 빈 문자열을 입력하면 정규화하지 않습니다. + + + A zone offset must be in the range %1..%2 inclusive. %3 is out of range. + 시간대 오프셋은 %1..%2 범위 안에 있어야 하며 이 두 값을 포함합니다. %3은(는) 범위를 벗어났습니다. + + + %1 is not a whole number of minutes. + %1은(는) 올바른 분 숫자가 아닙니다. + + + The URI cannot have a fragment + URI에는 조각이 올 수 없음 + + + Required cardinality is %1; got cardinality %2. + 필요한 농도는 %1이지만, %2이(가) 지정되었습니다. + + + The item %1 did not match the required type %2. + 항목 %1은(는) 필요한 형식 %2과(와) 일치하지 않습니다. + + + The variable %1 is unused + 변수 %1이(가) 사용되지 않습니다 + + + W3C XML Schema identity constraint selector + W3C XML 스키마 아이덴티티 제약 조건 선택자 + + + W3C XML Schema identity constraint field + W3C XML 스키마 아이덴티티 제약 조건 필드 + + + A construct was encountered which is disallowed in the current language(%1). + 현재 언어(%1)에 사용할 수 없는 생성자가 있습니다. + + + %1 is an unknown schema type. + %1은(는) 알 수 없는 스키마 형식입니다. + + + A template with name %1 has already been declared. + 이름이 %1인 템플릿이 이미 선언되었습니다. + + + %1 is not a valid numeric literal. + %1은(는) 올바른 숫자 리터럴이 아닙니다. + + + Only one %1 declaration can occur in the query prolog. + 쿼리 선두부에는 %1 선언이 하나만 올 수 있습니다. + + + The initialization of variable %1 depends on itself + 변수 %1의 초기화 과정이 자기 자신에게 의존함 + + + No variable with name %1 exists + 이름이 %1인 변수가 없음 + + + Version %1 is not supported. The supported XQuery version is 1.0. + 버전 %1은(는) 지원하지 않습니다. 지원하는 XQuery 버전은 1.0입니다. + + + The encoding %1 is invalid. It must contain Latin characters only, must not contain whitespace, and must match the regular expression %2. + 인코딩 %1은(는) 올바르지 않습니다. 라틴 알파벳만 포함해야 하며, 공백이 들어가지 않아야 하며, 정규 표현식 %2와(과) 일치해야 합니다. + + + No function with signature %1 is available + 선언이 %1인 함수가 없습니다 + + + A default namespace declaration must occur before function, variable, and option declarations. + 기본 네임스페이스 선언은 함수, 변수, 옵션 선언 이전에 와야 합니다. + + + Namespace declarations must occur before function, variable, and option declarations. + 네임스페이스 선언은 함수, 변수, 옵션 선언 이전에 와야 합니다. + + + Module imports must occur before function, variable, and option declarations. + 모듈 가져오기는 함수, 변수, 옵션 선언 이전에 와야 합니다. + + + The keyword %1 cannot occur with any other mode name. + 키워드 %1은(는) 다른 모드 이름과 같이 사용할 수 없습니다. + + + The value of attribute %1 must be of type %2, which %3 isn't. + 속성 %1의 값은 %2 형식이어야 하지만, %3은(는) 그렇지 않습니다. + + + It is not possible to redeclare prefix %1. + 접두사 %1을(를) 다시 선언할 수 없습니다. + + + The prefix %1 cannot be bound. By default, it is already bound to the namespace %2. + 접두사 %1이(가) 바인딩될 수 없습니다. 기본적으로 이 값은 네임스페이스 %2에 바인딩되어 있습니다. + + + Prefix %1 is already declared in the prolog. + 접두사 %1이(가) 선두부에 이미 선언되어 있습니다. + + + The name of an option must have a prefix. There is no default namespace for options. + 옵션의 이름은 접두사를 포함해야 합니다. 옵션에는 기본 네임스페이스가 없습니다. + + + The Schema Import feature is not supported, and therefore %1 declarations cannot occur. + 스키마 가져오기 기능은 지원하지 않으며, %1 선언이 올 수 없습니다. + + + The target namespace of a %1 cannot be empty. + %1의 대상 네임스페이스가 비어 있으면 안 됩니다. + + + The module import feature is not supported + 모듈 가져오기 기능은 지원하지 않습니다 + + + A variable with name %1 has already been declared. + 이름이 %1인 변수가 이미 선언되었습니다. + + + No value is available for the external variable with name %1. + 이름이 %1인 외부 변수의 사용할 수 있는 값이 없습니다. + + + A stylesheet function must have a prefixed name. + 스타일시트 함수는 접두사가 있는 이름을 가져야 합니다. + + + The namespace for a user defined function cannot be empty (try the predefined prefix %1 which exists for cases like this) + 사용자 정의 함수의 네임스페이스는 비어 있을 수 없습니다. (이러한 경우에 사용할 수 있는 미리 정의된 접두사 %1을(를) 사용하십시오) + + + The namespace %1 is reserved; therefore user defined functions may not use it. Try the predefined prefix %2, which exists for these cases. + 네임스페이스 %1은(는) 예약되어 있으므로 사용자 정의 함수에서 사용할 수 없습니다. 이러한 경우에 사용할 수 있는 미리 정의된 접두사 %2을(를) 사용하십시오. + + + The namespace of a user defined function in a library module must be equivalent to the module namespace. In other words, it should be %1 instead of %2 + 라이브러리 모듈에 있는 사용자 정의 함수의 네임스페이스는 모듈의 네임스페이스와 같아야 합니다. 즉 %2이(가) 아니라 %1이어야 합니다 + + + A function already exists with the signature %1. + 선언이 %1인 함수가 이미 존재합니다. + + + No external functions are supported. All supported functions can be used directly, without first declaring them as external + 외부 함수는 지원하지 않습니다. 모든 지원하는 함수는 external로 선언하지 않고 바로 사용할 수 있습니다 + + + An argument with name %1 has already been declared. Every argument name must be unique. + 이름이 %1인 인자가 이미 선언되었습니다. 모든 인자의 이름은 달라야 합니다. + + + When function %1 is used for matching inside a pattern, the argument must be a variable reference or a string literal. + 함수 %1이(가) 패턴 안쪽에서 일치하는 데 사용되는 경우에는 인자 형식이 변수 참조나 문자열 리터럴이어야 합니다. + + + In an XSL-T pattern, the first argument to function %1 must be a string literal, when used for matching. + XSL-T 패턴에서 함수 %1을(를) 일치하는 데 사용하려면 첫 번째 인자는 문자열 리터럴이어야 합니다. + + + In an XSL-T pattern, the first argument to function %1 must be a literal or a variable reference, when used for matching. + XSL-T 패턴에서 함수 %1을(를) 일치하는 데 사용하려면 첫 번째 인자 형식이 변수 참조나 문자열 리터럴이어야 합니다. + + + In an XSL-T pattern, function %1 cannot have a third argument. + XSL-T 패턴에서 함수 %1에는 세 번째 인자가 올 수 없습니다. + + + In an XSL-T pattern, only function %1 and %2, not %3, can be used for matching. + XSL-T 패턴에서 일치하는 데에는 함수 %1, %2만 사용할 수 있으며, %3은(는) 사용할 수 없습니다. + + + In an XSL-T pattern, axis %1 cannot be used, only axis %2 or %3 can. + XSL-T 패턴에서 축 %2, %3만 사용할 수 있으며, %1은(는) 사용할 수 없습니다. + + + %1 is an invalid template mode name. + %1은(는) 잘못된 템플릿 모드 이름입니다. + + + The name of a variable bound in a for-expression must be different from the positional variable. Hence, the two variables named %1 collide. + for 표현식에서 사용되는 바운딩된 변수의 이름은 위치 변수의 이름과 달라야 합니다. 따라서 두 변수 %1이(가) 충돌합니다. + + + The Schema Validation Feature is not supported. Hence, %1-expressions may not be used. + 스키마 검사 기능은 지원하지 않습니다. 따라서 %1 표현식은 사용할 수 없습니다. + + + None of the pragma expressions are supported. Therefore, a fallback expression must be present + pragma 표현식은 지원하지 않습니다. 따라서 폴백 표현식이 필요합니다 + + + Each name of a template parameter must be unique; %1 is duplicated. + 템플릿 인자의 이름은 중복되지 않아야 하므로 같은 이름 %1이(가) 충돌합니다. + + + The %1-axis is unsupported in XQuery + XQuery에서 %1 축은 지원하지 않음 + + + No function with name %1 is available. + 이름이 %1인 함수를 사용할 수 없습니다. + + + The namespace URI cannot be the empty string when binding to a prefix, %1. + 접두사 %1에 바인딩될 때 네임스페이스 URI는 빈 문자열일 수 없습니다. + + + %1 is an invalid namespace URI. + %1은(는) 잘못된 네임스페이스 URI입니다. + + + It is not possible to bind to the prefix %1 + 접두사 %1에 바인딩할 수 없습니다 + + + Namespace %1 can only be bound to %2 (and it is, in either case, pre-declared). + 네임스페이스 %1은(는) %2에만 바인딩할 수 있습니다 (미리 선언되어야 합니다). + + + Prefix %1 can only be bound to %2 (and it is, in either case, pre-declared). + 접두사 %1은(는) %2에만 바인딩할 수 있습니다 (미리 선언되어야 합니다). + + + Two namespace declaration attributes have the same name: %1. + 두 네임스페이스 선언 속성의 이름이 중복됩니다: %1. + + + The namespace URI must be a constant and cannot use enclosed expressions. + 네임스페이스 URI는 상수여야 하며 내장된 표현식을 사용할 수 없습니다. + + + An attribute with name %1 has already appeared on this element. + 이름이 %1인 속성이 이 원소에 이미 나타났습니다. + + + A direct element constructor is not well-formed. %1 is ended with %2. + 직접 원소 생성자의 형식이 올바르지 않습니다. %1이(가) %2(으)로 끝납니다. + + + The name %1 does not refer to any schema type. + 이름 %1은(는) 어떠한 스키마 형식도 참조하지 않습니다. + + + %1 is an complex type. Casting to complex types is not possible. However, casting to atomic types such as %2 works. + %1은(는) 복합 형식입니다. 복합 형식으로 캐스팅은 불가능하지만, %2와(과) 같은 원자적 형식으로의 캐스팅은 가능합니다. + + + %1 is not an atomic type. Casting is only possible to atomic types. + %1은(는) 원자적 타입이 아닙니다. 원자적 타입으로만 변환할 수 있습니다. + + + %1 is not a valid name for a processing-instruction. + %1은(는) 올바른 처리 방법 이름이 아닙니다. + + + %1 is not in the in-scope attribute declarations. Note that the schema import feature is not supported. + %1은(는) 범위 내에 있는 속성 선언에 존재하지 않습니다. 스키마 가져오기 기능은 지원하지 않습니다. + + + The name of an extension expression must be in a namespace. + 확장 표현식의 이름은 네임스페이스 안에 있어야 합니다. + + + Element %1 is not allowed at this location. + 이 위치에 원소 %1이(가) 올 수 없습니다. + + + Text nodes are not allowed at this location. + 이 위치에 텍스트 노드가 올 수 없습니다. + + + Parse error: %1 + 처리 오류: %1 + + + The value of the XSL-T version attribute must be a value of type %1, which %2 isn't. + XSL-T 버전 속성의 값은 %1 형식이어야 하며, %2은(는) 이 형식이 아닙니다. + + + Running an XSL-T 1.0 stylesheet with a 2.0 processor. + XSL-T 1.0 스타일시트를 2.0 프로세서로 실행하고 있습니다. + + + Unknown XSL-T attribute %1. + 알 수 없는 XSL-T 속성 %1. + + + Attribute %1 and %2 are mutually exclusive. + 속성 %1와(과) %2은(는) 상호 배제적입니다. + + + In a simplified stylesheet module, attribute %1 must be present. + 간단한 스타일시트 모듈에서 속성 %1은(는) 반드시 존재해야 합니다. + + + If element %1 has no attribute %2, it cannot have attribute %3 or %4. + 원소 %1에 속성 %2이(가) 없으면, 속성 %3 또는 %4을(를) 가질 수 없습니다. + + + Element %1 must have at least one of the attributes %2 or %3. + 원소 %1에는 %2, %3 중 최소한 하나의 속성이 있어야 합니다. + + + At least one mode must be specified in the %1-attribute on element %2. + 원소 %2의 %1 속성에는 최소한 하나의 모드가 지정되어야 합니다. + + + Element %1 must come last. + 원소 %1은(는) 맨 마지막에 와야 합니다. + + + At least one %1-element must occur before %2. + 최소한 하나의 %1 원소가 %2 이전에 와야 합니다. + + + Only one %1-element can appear. + %1 원소는 최대 하나만 올 수 있습니다. + + + At least one %1-element must occur inside %2. + %2 안에 최소한 하나의 %1 원소가 와야 합니다. + + + When attribute %1 is present on %2, a sequence constructor cannot be used. + 속성 %1이(가) %2에 존재하면 시퀀스 생성자를 사용할 수 없습니다. + + + Element %1 must have either a %2-attribute or a sequence constructor. + 원소 %1은(는) %2 속성이나 시퀀스 생성자 중 하나를 가져야 합니다. + + + When a parameter is required, a default value cannot be supplied through a %1-attribute or a sequence constructor. + 인자가 필요한 경우에는 %1 속성이나 시퀀스 생성자를 통해서 기본값을 지정할 수 없습니다. + + + Element %1 cannot have children. + 원소 %1은(는) 자식을 가질 수 없습니다. + + + Element %1 cannot have a sequence constructor. + 원소 %1은(는) 시퀀스 생성자를 가질 수 없습니다. + + + The attribute %1 cannot appear on %2, when it is a child of %3. + 속성 %1은(는) %3의 자식일 때 %2에 나타날 수 없습니다. + + + A parameter in a function cannot be declared to be a tunnel. + 함수의 인자는 터널로 선언될 수 없습니다. + + + This processor is not Schema-aware and therefore %1 cannot be used. + 이 프로세서는 스키마를 인지하지 못하므로 %1을(를) 사용할 수 없습니다. + + + Top level stylesheet elements must be in a non-null namespace, which %1 isn't. + 최상위 스타일시트 원소는 비어 있지 않은 네임스페이스에 있어야 하지만 %1은(는) 그렇지 않습니다. + + + The value for attribute %1 on element %2 must either be %3 or %4, not %5. + 원소 %2의 속성 %1의 값은 %3, %4여야 하며, %5이(가) 올 수 없습니다. + + + Attribute %1 cannot have the value %2. + 속성 %1은(는) 값 %2을(를) 가질 수 없습니다. + + + The attribute %1 can only appear on the first %2 element. + 속성 %1은(는) 첫 %2 원소에만 올 수 있습니다. + + + At least one %1 element must appear as child of %2. + %2 원소의 자식으로 최소한 하나의 %1 원소가 와야 합니다. + + + Empty particle cannot be derived from non-empty particle. + 비어 있지 않은 입자에서 비어 있는 입자가 파생될 수 없습니다. + + + Derived particle is missing element %1. + 파생된 입자에 %1 원소가 없습니다. + + + Derived element %1 is missing value constraint as defined in base particle. + 파생된 원소 %1에는 기본 입자에 선언되어 있는 값 제약 조건이 없습니다. + + + Derived element %1 has weaker value constraint than base particle. + 파생된 원소 %1은(는) 기본 입자보다 약한 값 제약 조건을 가지고 있습니다. + + + Fixed value constraint of element %1 differs from value constraint in base particle. + 원소 %1의 고정 값 제약 조건은 부모 입자의 값 제약 조건과 다릅니다. + + + Derived element %1 cannot be nillable as base element is not nillable. + 기본 원소에 nil 값이 올 수 없으므로 파생된 원소 %1에도 nil 값이 올 수 없습니다. + + + Block constraints of derived element %1 must not be more weaker than in the base element. + 파생된 원소 %1의 블럭 제약 조건은 기본 원소의 제약 조건보다 약할 수 없습니다. + + + Simple type of derived element %1 cannot be validly derived from base element. + 파생된 원소 %1의 간단한 형식은 기본 원소에서 올바르게 파생될 수 없습니다. + + + Complex type of derived element %1 cannot be validly derived from base element. + 파생된 원소 %1의 복합 형식은 기본 원소에서 올바르게 파생될 수 없습니다. + + + Element %1 is missing in derived particle. + 원소 %1이(가) 파생된 입자에 없습니다. + + + Element %1 does not match namespace constraint of wildcard in base particle. + 원소 %1은(는) 기본 입자의 와일드카드 네임스페이스 제약 조건과 일치하지 않습니다. + + + Wildcard in derived particle is not a valid subset of wildcard in base particle. + 파생 입자의 와일드카드는 기본 입자의 와일드카드의 올바른 부분 집합이 아닙니다. + + + processContent of wildcard in derived particle is weaker than wildcard in base particle. + 파생 입자의 와일드카드의 processContent는 기본 입자의 와일드카드보다 약합니다. + + + Derived particle allows content that is not allowed in the base particle. + 기본 입자에서 허용하지 않는 내용이 파생 입자에 올 수 있습니다. + + + %1 has inheritance loop in its base type %2. + %1의 부모 형식 %2에서 상속 루프가 발견되었습니다. + + + Circular inheritance of base type %1. + 기본 형식 %1의 순환 상속입니다. + + + Circular inheritance of union %1. + 공용체 %1의 순환 상속입니다. + + + %1 is not allowed to derive from %2 by restriction as the latter defines it as final. + %1은(는) %2에서 final로 선언되었기 때문에 제한으로 분기될 수 없습니다. + + + %1 is not allowed to derive from %2 by extension as the latter defines it as final. + %1은(는) %2에서 final로 선언되었기 때문에 확장으로 분기될 수 없습니다. + + + Base type of simple type %1 cannot be complex type %2. + 간단한 형식 %1의 기본 형식은 복합 형식 %2일 수 없습니다. + + + Simple type %1 cannot have direct base type %2. + 간단한 형식 %1은(는) 직접적인 기본 형식 %2을(를) 가질 수 없습니다. + + + Simple type %1 is not allowed to have base type %2. + 간단한 형식 %1에는 기본 형식 %2가 올 수 없습니다. + + + Simple type %1 can only have simple atomic type as base type. + 간단한 형식 %1은(는) 간단한 원자적 형식만을 기본 형식으로 가질 수 있습니다. + + + Simple type %1 cannot derive from %2 as the latter defines restriction as final. + 형식 %2이(가) final로 선언되었으므로, 간단한 형식 %1은(는) 여기에서 파생될 수 없습니다. + + + Variety of item type of %1 must be either atomic or union. + %1 형식의 항목의 파생형은 원자적이거나 공용체여야 합니다. + + + Variety of member types of %1 must be atomic. + %1 형식의 항목의 파생형은 원자적이어야 합니다. + + + %1 is not allowed to derive from %2 by list as the latter defines it as final. + %1은(는) %2에서 final로 선언되었기 때문에 목록으로 분기될 수 없습니다. + + + Simple type %1 is only allowed to have %2 facet. + 간단한 형식 %1은(는) %2 패싯만 포함할 수 있습니다. + + + Base type of simple type %1 must have variety of type list. + 간단한 형식 %1의 기본 형식은 파생형 목록을 가져야 합니다. + + + Base type of simple type %1 has defined derivation by restriction as final. + 간단한 형식 %1의 기본 형식이 final로 선언되어 있어서 파생이 제한되어 있습니다. + + + Item type of base type does not match item type of %1. + 기본 형식의 항목 형식이 %1의 항목 형식과 일치하지 않습니다. + + + Simple type %1 contains not allowed facet type %2. + 간단한 형식 %1에 허용되지 않는 패싯 형식 %2이(가) 존재합니다. + + + %1 is not allowed to derive from %2 by union as the latter defines it as final. + %1은(는) %2에서 final로 선언되었기 때문에 공용체로 분기될 수 없습니다. + + + %1 is not allowed to have any facets. + %1에는 패싯을 추가할 수 없습니다. + + + Base type %1 of simple type %2 must have variety of union. + 간단한 형식 %2의 기본 형식 %1에는 공용체의 파생형이 있어야 합니다. + + + Base type %1 of simple type %2 is not allowed to have restriction in %3 attribute. + 간단한 형식 %2의 기본 형식 %1에는 %3 속성에 제한을 걸 수 없습니다. + + + Member type %1 cannot be derived from member type %2 of %3's base type %4. + %3의 기본 형식 %4의 형식 %2 멤버 형식에서 멤버 형식 %1을(를) 파생할 수 없습니다. + + + Derivation method of %1 must be extension because the base type %2 is a simple type. + 기본 형식 %2이(가) 간단한 형식이므로 %1의 파생 방식은 확장이어야 합니다. + + + Complex type %1 has duplicated element %2 in its content model. + 복합 형식 %1의 내용 모델에 중복된 원소 %2이(가) 있습니다. + + + Complex type %1 has non-deterministic content. + 복합 형식 %1에 비 결정적 내용이 있습니다. + + + Attributes of complex type %1 are not a valid extension of the attributes of base type %2: %3. + 복합 형식 %1의 속성이 기본 형식 %2의 속성의 올바른 확장이 아닙니다: %3. + + + Content model of complex type %1 is not a valid extension of content model of %2. + 복합 형식 %1의 내용 모델이 %2의 내용 모델의 올바른 확장이 아닙니다. + + + Complex type %1 must have simple content. + 복합 형식 %1에는 간단한 내용이 있어야 합니다. + + + Complex type %1 must have the same simple type as its base class %2. + 복합 형식 %1은(는) 기본 클래스 %2와(과) 같은 간단한 형식이 필요합니다. + + + Complex type %1 cannot be derived from base type %2%3. + 복합 형식 %1은(는) 기본 형식 %2%3에서 파생될 수 없습니다. + + + Attributes of complex type %1 are not a valid restriction from the attributes of base type %2: %3. + 복합 형식 %1의 속성에 기본 형식 %2의 속성에서 온 올바른 제한이 없음: %3. + + + Complex type %1 with simple content cannot be derived from complex base type %2. + 간단한 내용이 있는 복합 형식 %1은(는) 복합 기본 형식 %2에서 파생될 수 없습니다. + + + Item type of simple type %1 cannot be a complex type. + 간단한 형식 %1의 항목 형식은 복합 형식이 될 수 없습니다. + + + Member type of simple type %1 cannot be a complex type. + 간단한 형식 %1의 구성원 형식은 복합 형식이 될 수 없습니다. + + + %1 is not allowed to have a member type with the same name as itself. + %1에는 자기 자신을 종류로 갖는 구성 요소를 추가할 수 없습니다. + + + %1 facet collides with %2 facet. + %1와(과) %2 패싯이 충돌합니다. + + + %1 facet must have the same value as %2 facet of base type. + %1 패싯은 기본 형식의 패싯 %2와(과) 같은 값을 가져야 합니다. + + + %1 facet must be equal or greater than %2 facet of base type. + %1 패싯은 기본 형식의 %2 패싯의 값보다 크거나 같아야 합니다. + + + %1 facet must be less than or equal to %2 facet of base type. + %1 패싯은 기본 형식의 %2 패싯의 값보다 작거나 같아야 합니다. + + + %1 facet contains invalid regular expression + %1 패싯에 잘못된 정규 표현식이 있음 + + + Unknown notation %1 used in %2 facet. + %2 패싯에 알 수 없는 표기법 %1이(가) 사용되었습니다. + + + %1 facet contains invalid value %2: %3. + %1 패싯에 잘못된 값 %2이(가) 포함됨: %3. + + + %1 facet cannot be %2 or %3 if %4 facet of base type is %5. + %1 패싯은 기본 형식의 %4 패싯이 %5 형식일 때 %2, %3일 수 없습니다. + + + %1 facet cannot be %2 if %3 facet of base type is %4. + %1 패싯은 기본 형식의 %3 패싯이 %4 형식일 때 %2일 수 없습니다. + + + %1 facet must be less than or equal to %2 facet. + %1 패싯은 %2 패싯보다 작거나 같아야 합니다. + + + %1 facet must be less than %2 facet of base type. + %1 패싯은 기본 형식의 %2 패싯보다 작아야 합니다. + + + %1 facet and %2 facet cannot appear together. + %1 패싯과 %2 패싯은 같이 등장할 수 없습니다. + + + %1 facet must be greater than %2 facet of base type. + %1 패싯은 기본 형식의 %2 패싯보다 커야 합니다. + + + %1 facet must be less than %2 facet. + %1 패싯은 %2 패싯보다 작아야 합니다. + + + %1 facet must be greater than or equal to %2 facet of base type. + %1 패싯은 기본 형식의 %2 패싯보다 크거나 같아야 합니다. + + + Simple type contains not allowed facet %1. + 간단한 형식에는 패싯 %1이(가) 올 수 없습니다. + + + %1, %2, %3, %4, %5 and %6 facets are not allowed when derived by list. + 목록에서 파생된 경우 %1, %2, %3, %4, %5, %6 패싯은 허용되지 않습니다. + + + Only %1 and %2 facets are allowed when derived by union. + 공용체에서 파생되었을 때에는 %1, %2 패싯만 사용할 수 있습니다. + + + %1 contains %2 facet with invalid data: %3. + %1에 잘못된 데이터가 들어 있는 %2 패싯이 있음: %3. + + + Attribute group %1 contains attribute %2 twice. + 속성 그룹 %1에 속성 %2이(가) 두 번 들어 있습니다. + + + Attribute group %1 contains two different attributes that both have types derived from %2. + 속성 그룹 %1에 %2에서 파생된 형식을 포함하는 두 개의 서로 다른 속성이 있습니다. + + + Attribute group %1 contains attribute %2 that has value constraint but type that inherits from %3. + 속성 그룹 %1에 값 제약 조건이 있지만 %3 형식에서 파생된 형식을 갖는 %2 속성이 있습니다. + + + Complex type %1 contains attribute %2 twice. + 복합 형식 %1에 속성 %2이(가) 두 번 들어 있습니다. + + + Complex type %1 contains two different attributes that both have types derived from %2. + 복합 형식 %1에 %2에서 파생된 형식을 포함하는 두 개의 서로 다른 속성이 있습니다. + + + Complex type %1 contains attribute %2 that has value constraint but type that inherits from %3. + 복합 형식 %1에 값 제약 조건이 있지만 %3 형식에서 파생된 형식을 갖는 %2 속성이 있습니다. + + + Element %1 is not allowed to have a value constraint if its base type is complex. + 기본 형식이 complex인 경우 원소 %1은(는) 값 제약 조건을 가질 수 없습니다. + + + Element %1 is not allowed to have a value constraint if its type is derived from %2. + 형식이 %2에서 파생된 경우 원소 %1은(는) 값 제약 조건을 가질 수 없습니다. + + + Value constraint of element %1 is not of elements type: %2. + 원소 %1의 값 제약 조건이 elements 형식이 아님: %2. + + + Element %1 is not allowed to have substitution group affiliation as it is no global element. + 원소 %1은(는) 전역 원소가 아니므로 대체 그룹 친화성을 가질 수 없습니다. + + + Type of element %1 cannot be derived from type of substitution group affiliation. + 원소 %1의 형식은 대체 그룹 친화력의 형식에서 파생될 수 없습니다. + + + Value constraint of attribute %1 is not of attributes type: %2. + 속성 %1의 값 제약이 attributes 형식이 아님: %2. + + + Attribute %1 has value constraint but has type derived from %2. + 속성 %1에는 값 제약이 있지만 %2 형식에서 파생된 형식을 가지고 있습니다. + + + %1 attribute in derived complex type must be %2 like in base type. + 파생된 복합체 형식의 %1 속성은 기본 형식처럼 %2 형식의 값을 가져야 합니다. + + + Attribute %1 in derived complex type must have %2 value constraint like in base type. + 파생된 복합 형식의 속성 %1은(는) 기본 형식처럼 값 제약 %2을(를) 가져야 합니다. + + + Attribute %1 in derived complex type must have the same %2 value constraint like in base type. + 파생된 복합 형식의 속성 %1은(는) 기본 형식과 같은 값 제약 %2을(를) 가져야 합니다. + + + Attribute %1 in derived complex type must have %2 value constraint. + 파생된 복합체 형식의 %1 속성은 %2 형식의 값 제약을 가져야 합니다. + + + processContent of base wildcard must be weaker than derived wildcard. + 기본 와일드카드의 processContent는 파생 와일드카드보다 약해야 합니다. + + + Element %1 exists twice with different types. + 서로 다른 형식의 원소 %1이(가) 존재합니다. + + + Particle contains non-deterministic wildcards. + 입자에 비 결정적인 와일드카드가 존재합니다. + + + Base attribute %1 is required but derived attribute is not. + 기본 속성 %1이(가) 필요하지만 파생 속성은 필요하지 않습니다. + + + Type of derived attribute %1 cannot be validly derived from type of base attribute. + 파생 속성 %1의 형식이 기본 속성의 형식에서 올바르게 파생될 수 없습니다. + + + Value constraint of derived attribute %1 does not match value constraint of base attribute. + 파생 속성 %1의 값 제약이 기본 속성의 값 제약과 일치하지 않습니다. + + + Derived attribute %1 does not exist in the base definition. + 파생 속성 %1이(가) 기본 정의에 없습니다. + + + Derived attribute %1 does not match the wildcard in the base definition. + 파생 속성 %1이(가) 기본 속성의 와일드카드와 일치하지 않습니다. + + + Base attribute %1 is required but missing in derived definition. + 기본 속성 %1이(가) 필요하지만 파생 정의에 없습니다. + + + Derived definition contains an %1 element that does not exists in the base definition + 파생 정의에서 기본 정의에 없는 %1 원소를 포함합니다 + + + Derived wildcard is not a subset of the base wildcard. + 파생 와일드카드가 기본 와일드카드의 부분 집합이 아닙니다. + + + %1 of derived wildcard is not a valid restriction of %2 of base wildcard + 파생 와일드카드의 %1은(는) 기본 와일드카드의 %2의 올바른 제약 조건이 아닙니다 + + + Attribute %1 from base type is missing in derived type. + 기본 형식의 속성 %1이(가) 파생 형식에 없습니다. + + + Type of derived attribute %1 differs from type of base attribute. + 파생 속성 %1의 형식이 기본 속성과 다릅니다. + + + Base definition contains an %1 element that is missing in the derived definition + 파생 정의에 없는 %1 원소가 기본 정의에 포함되어 있습니다 + + + Can not process unknown element %1, expected elements are: %2. + 알 수 없는 원소 %1을(를) 처리할 수 없습니다. 예상하는 원소는 다음과 같습니다: %2. + + + Element %1 is not allowed in this scope, possible elements are: %2. + 원소 %1은(는) 이 범위에 올 수 없습니다. 가능한 원소는 다음과 같습니다: %2. + + + Child element is missing in that scope, possible child elements are: %1. + 그 범위에 자식 원소가 없습니다. 가능한 자식 원소는 다음과 같습니다: %1. + + + Document is not a XML schema. + 문서가 XML 스키마가 아닙니다. + + + %1 attribute of %2 element contains invalid content: {%3} is not a value of type %4. + %2 원소의 %1 속성에 올바르지 않은 내용이 있음: {%3}은(는) %4 형식의 값이 아님. + + + %1 attribute of %2 element contains invalid content: {%3}. + %2 원소의 %1 속성에 올바르지 않은 내용이 있음: {%3}. + + + Target namespace %1 of included schema is different from the target namespace %2 as defined by the including schema. + 포함된 스키마의 대상 네임스페이스 %1은(는) 포함하는 스키마에 정의된 대상 네임스페이스 %2와(과) 다릅니다. + + + Target namespace %1 of imported schema is different from the target namespace %2 as defined by the importing schema. + 가져온 스키마의 대상 네임스페이스 %1은(는) 가져온 스키마에 정의된 대상 네임스페이스 %2와(과) 다릅니다. + + + %1 element is not allowed to have the same %2 attribute value as the target namespace %3. + 원소 %1의 속성 %2의 값으로는 대상 네임스페이스 %3와(과) 같은 값이 올 수 없습니다. + + + %1 element without %2 attribute is not allowed inside schema without target namespace. + 대상 네임스페이스가 없는 스키마에는 %2 속성이 없는 %1 원소가 올 수 없습니다. + + + %1 element is not allowed inside %2 element if %3 attribute is present. + %3 속성이 존재하면 %2 원소 안에 %1 원소가 올 수 없습니다. + + + %1 element has neither %2 attribute nor %3 child element. + %1 원소에 %2 속성이나 %3 자식 원소가 없습니다. + + + %1 element with %2 child element must not have a %3 attribute. + %2 자식 원소가 있는 %1 원소에는 %3 속성이 존재할 수 없습니다. + + + %1 attribute of %2 element must be %3 or %4. + %2 원소의 %1 속성은 %3(이)나 %4여야 합니다. + + + %1 attribute of %2 element must have a value of %3. + %2 원소의 %1 속성은 %3 형식의 값을 가져야 합니다. + + + %1 attribute of %2 element must have a value of %3 or %4. + %2 원소의 %1 속성은 값 %3(이)나 %4이(가) 있어야 합니다. + + + %1 element must not have %2 and %3 attribute together. + %1 원소는 %2, %3 속성 둘 다를 가질 수 없습니다. + + + Content of %1 attribute of %2 element must not be from namespace %3. + %2 원소의 %1 속성의 내용은 %3 네임스페이스에서 올 수 없습니다. + + + %1 attribute of %2 element must not be %3. + %2 원소의 %1 속성은 %3일 수 없습니다. + + + %1 attribute of %2 element must have the value %3 because the %4 attribute is set. + %4 속성이 설정되어 있으므로 %2 원소의 %1 속성 값으로는 %3이(가) 지정되어야 합니다. + + + Specifying use='prohibited' inside an attribute group has no effect. + 속성 그룹 안에서 use='prohibited'를 사용하여도 효과가 없습니다. + + + %1 element must have either %2 or %3 attribute. + %1 원소는 %2, %3 중 하나의 속성만 가져야 합니다. + + + %1 element must have either %2 attribute or %3 or %4 as child element. + %1 원소는 %2 속성이나 자식 원소로 %3, %4을(를) 가져야 합니다. + + + %1 element requires either %2 or %3 attribute. + %1 원소에는 %2, %3 중 하나의 속성이 필요합니다. + + + Text or entity references not allowed inside %1 element + %1 원소 안에 텍스트나 엔티티 참조를 사용할 수 없음 + + + %1 attribute of %2 element must contain %3, %4 or a list of URIs. + %2 원소의 %1 속성에는 %3, %4, 또는 URI 목록이 포함되어야 합니다. + + + %1 element is not allowed in this context. + 이 컨텍스트에는 %1 원소가 허용되지 않습니다. + + + %1 attribute of %2 element has larger value than %3 attribute. + %2 원소의 %1 속성이 %3 속성보다 큰 값을 가지고 있습니다. + + + Prefix of qualified name %1 is not defined. + 접두사나 완전한 이름 %1이(가) 정의되지 않았습니다. + + + %1 attribute of %2 element must either contain %3 or the other values. + %2 원소의 %1 속성에는 %3(이)나 다른 값이 포함되어야 합니다. + + + Component with ID %1 has been defined previously. + ID가 %1인 구성 요소가 이미 정의되었습니다. + + + Element %1 already defined. + 원소 %1이(가) 이미 정의되었습니다. + + + Attribute %1 already defined. + 속성 %1이(가) 이미 정의되었습니다. + + + Type %1 already defined. + 형식 %1이(가) 이미 정의되었습니다. + + + Type %1 already defined. + QSystemSemaphore + %1: 이미 존재함 + + + Attribute group %1 already defined. + 속성 그룹 %1이(가) 이미 정의되었습니다. + + + Element group %1 already defined. + 원소 그룹 %1이(가) 이미 정의되었습니다. + + + Notation %1 already defined. + 표기법 %1이(가) 이미 정의되었습니다. + + + Identity constraint %1 already defined. + 아이덴티티 제약 조건 %1이(가) 이미 정의되었습니다. + + + Duplicated facets in simple type %1. + 간단한 형식 %1에 중복된 패싯이 있습니다. + + + %1 references unknown %2 or %3 element %4. + %1에서 알 수 없는 %2 또는 %3 원소 %4을(를) 참조합니다. + + + %1 references identity constraint %2 that is no %3 or %4 element. + %1에서 %3, %4 원소가 없는 아이덴티티 제약 조건 %2을(를) 참조합니다. + + + %1 has a different number of fields from the identity constraint %2 that it references. + %1에서 참조하는 아이덴티티 제약 조건 %2와(과) 필드 개수가 다릅니다. + + + Base type %1 of %2 element cannot be resolved. + %2 원소의 기본 형식 %1을(를) 해석할 수 없습니다. + + + Item type %1 of %2 element cannot be resolved. + %2 원소의 항목 형식 %1을(를) 해석할 수 없습니다. + + + Member type %1 of %2 element cannot be resolved. + %2 원소의 구성 요소 형식 %1을(를) 해석할 수 없습니다. + + + Type %1 of %2 element cannot be resolved. + %2 원소의 형식 %1을(를) 해석할 수 없습니다. + + + Base type %1 of complex type cannot be resolved. + 복합 형식 %1의 기본 형식을 해석할 수 없습니다. + + + %1 cannot have complex base type that has a %2. + %1에는 %2을(를) 포함하는 복합 기본 형식을 추가할 수 없음. + + + Content model of complex type %1 contains %2 element so it cannot be derived by extension from a non-empty type. + 복합 형식 %1의 내용 모델은 %2 원소를 포함하므로 비어 있지 않은 형식의 확장으로 파생될 수 없습니다. + + + Complex type %1 cannot be derived by extension from %2 as the latter contains %3 element in its content model. + 복합 형식 %1은(는) %2의 내용 모델에 %3 원소를 포함하므로 여기에서 확장으로 파생될 수 없습니다. + + + Type of %1 element must be a simple type, %2 is not. + %1 원소의 형식은 간단한 형식이어야 하며, %2은(는) 그렇지 않습니다. + + + Substitution group %1 of %2 element cannot be resolved. + %2의 대체 그룹 %1을(를) 해석할 수 없습니다. + + + Substitution group %1 has circular definition. + 대체 그룹 %1에 순환 정의가 있습니다. + + + Duplicated element names %1 in %2 element. + %2 원소에 중복된 원소 이름 %1이(가) 있습니다. + + + Reference %1 of %2 element cannot be resolved. + %2 원소의 참조 %1을(를) 해석할 수 없습니다. + + + Circular group reference for %1. + %1의 순환 그룹 참조가 발견되었습니다. + + + %1 element is not allowed in this scope + 이 범위에 %1 원소가 올 수 없습니다 + + + %1 element cannot have %2 attribute with value other than %3. + %1 원소의 %2 속성 값은 %3이어야 합니다. + + + %1 element cannot have %2 attribute with value other than %3 or %4. + %1 원소의 %2 속성 값은 %3(이)나 %4여야 합니다. + + + %1 or %2 attribute of reference %3 does not match with the attribute declaration %4. + 참조 %3의 속성 %1이나 %2이(가) 속성 선언 %4와(과) 일치하지 않습니다. + + + Attribute group %1 has circular reference. + 속성 그룹 %1에 순환 참조가 있습니다. + + + %1 attribute in %2 must have %3 use like in base type %4. + %2의 %1 속성은 기본 형식 %4처럼 %3을(를) 사용하여야 합니다. + + + Attribute wildcard of %1 is not a valid restriction of attribute wildcard of base type %2. + %1의 속성 와일드카드는 기본 형식 %2의 속성 와일드카드의 올바른 제한이 아닙니다. + + + %1 has attribute wildcard but its base type %2 has not. + %1에는 속성 와일드카드가 있지만 기본 형식 %2에는 없습니다. + + + Union of attribute wildcard of type %1 and attribute wildcard of its base type %2 is not expressible. + %1 형식의 속성 와일드카드와 기본 형식 %2의 속성 와일드카드의 공용체는 표현할 수 없습니다. + + + Enumeration facet contains invalid content: {%1} is not a value of type %2. + Enumeration 패싯에 올바르지 않은 내용이 있습니다: {%1}은(는) %2 형식의 값이 아닙니다. + + + Namespace prefix of qualified name %1 is not defined. + 완전한 이름 %1을(를) 사용하는 네임스페이스 접두사가 선언되지 않았습니다. + + + %1 element %2 is not a valid restriction of the %3 element it redefines: %4. + %1 원소 %2은(는) 재정의하는 %3 원소의 올바른 제약 조건이 아닙니다: %4. + + + %1 is not valid according to %2. + %2에 의하면 %1은(는) 올바르지 않습니다. + + + String content does not match the length facet. + 문자열 내용이 length 패싯과 일치하지 않습니다. + + + String content does not match the minLength facet. + 문자열 내용이 minLength 패싯과 일치하지 않습니다. + + + String content does not match the maxLength facet. + 문자열 내용이 maxLength 패싯과 일치하지 않습니다. + + + String content does not match pattern facet. + 문자열 내용이 pattern 패싯과 일치하지 않습니다. + + + String content is not listed in the enumeration facet. + 문자열 내용이 enumeration 패싯과 일치하지 않습니다. + + + Signed integer content does not match the maxInclusive facet. + 부호 있는 정수 내용이 maxInclusive 패싯과 일치하지 않습니다. + + + Signed integer content does not match the maxExclusive facet. + 부호 있는 정수 내용이 maxExclusive 패싯과 일치하지 않습니다. + + + Signed integer content does not match the minInclusive facet. + 부호 있는 정수 내용이 minInclusive 패싯과 일치하지 않습니다. + + + Signed integer content does not match the minExclusive facet. + 부호 있는 정수 내용이 minExclusive 패싯과 일치하지 않습니다. + + + Signed integer content is not listed in the enumeration facet. + 부호 있는 정수 내용이 enumeration 패싯에 없습니다. + + + Signed integer content does not match pattern facet. + 부호 있는 정수 내용이 pattern 패싯과 일치하지 않습니다. + + + Signed integer content does not match in the totalDigits facet. + 부호 있는 정수 내용이 totalDigits 패싯과 일치하지 않습니다. + + + Unsigned integer content does not match the maxInclusive facet. + 부호 없는 정수 내용이 maxInclusive 패싯과 일치하지 않습니다. + + + Unsigned integer content does not match the maxExclusive facet. + 부호 없는 정수 내용이 maxExclusive 패싯과 일치하지 않습니다. + + + Unsigned integer content does not match the minInclusive facet. + 부호 없는 정수 내용이 minInclusive 패싯과 일치하지 않습니다. + + + Unsigned integer content does not match the minExclusive facet. + 부호 없는 정수 내용이 minExclusive 패싯과 일치하지 않습니다. + + + Unsigned integer content is not listed in the enumeration facet. + 부호 없는 정수 내용이 enumeration 패싯에 없습니다. + + + Unsigned integer content does not match pattern facet. + 부호 없는 정수 내용이 pattern 패싯과 일치하지 않습니다. + + + Unsigned integer content does not match in the totalDigits facet. + 부호 없는 정수 내용이 totalDigits 패싯과 일치하지 않습니다. + + + Double content does not match the maxInclusive facet. + 실수 내용이 maxLength 패싯과 일치하지 않습니다. + + + Double content does not match the maxExclusive facet. + 실수 내용이 maxExclusive 패싯과 일치하지 않습니다. + + + Double content does not match the minInclusive facet. + 실수 내용이 minInclusive 패싯과 일치하지 않습니다. + + + Double content does not match the minExclusive facet. + 실수 내용이 minExclusive 패싯과 일치하지 않습니다. + + + Double content is not listed in the enumeration facet. + 실수 내용이 enumeration 패싯과 일치하지 않습니다. + + + Double content does not match pattern facet. + 실수 내용이 pattern 패싯과 일치하지 않습니다. + + + Decimal content does not match in the fractionDigits facet. + 십진수 내용이 fractionDigits 패싯과 일치하지 않습니다. + + + Decimal content does not match in the totalDigits facet. + 십진수 내용이 totalDigits 패싯과 일치하지 않습니다. + + + Date time content does not match the maxInclusive facet. + 날짜 및 시간 내용이 maxInclusive 패싯과 일치하지 않습니다. + + + Date time content does not match the maxExclusive facet. + 날짜 및 시간 내용이 maxExclusive 패싯과 일치하지 않습니다. + + + Date time content does not match the minInclusive facet. + 날짜 및 시간 내용이 minInclusive 패싯과 일치하지 않습니다. + + + Date time content does not match the minExclusive facet. + 날짜 및 시간 내용이 minExclusive 패싯과 일치하지 않습니다. + + + Date time content is not listed in the enumeration facet. + 날짜 및 시간 내용이 enumeration 패싯에 없습니다. + + + Date time content does not match pattern facet. + 날짜 및 시간 내용이 pattern 패싯과 일치하지 않습니다. + + + Duration content does not match the maxInclusive facet. + 지속 시간 내용이 maxInclusive 패싯과 일치하지 않습니다. + + + Duration content does not match the maxExclusive facet. + 지속 시간 내용이 maxExclusive 패싯과 일치하지 않습니다. + + + Duration content does not match the minInclusive facet. + 지속 시간 내용이 minInclusive 패싯과 일치하지 않습니다. + + + Duration content does not match the minExclusive facet. + 지속 시간 내용이 minExclusive 패싯과 일치하지 않습니다. + + + Duration content is not listed in the enumeration facet. + 지속 시간 내용이 enumeration 패싯에 없습니다. + + + Duration content does not match pattern facet. + 지속 시간 내용이 pattern 패싯과 일치하지 않습니다. + + + Boolean content does not match pattern facet. + 참/거짓 내용이 pattern 패싯과 일치하지 않습니다. + + + Binary content does not match the length facet. + 참/거짓 내용이 length 패싯과 일치하지 않습니다. + + + Binary content does not match the minLength facet. + 참/거짓 내용이 minLength 패싯과 일치하지 않습니다. + + + Binary content does not match the maxLength facet. + 참/거짓 내용이 maxLength 패싯과 일치하지 않습니다. + + + Binary content is not listed in the enumeration facet. + 참/거짓 내용이 enumeration 패싯에 없습니다. + + + Invalid QName content: %1. + 잘못된 QName 내용: %1. + + + QName content is not listed in the enumeration facet. + QName 내용이 enumeration 패싯에 없습니다. + + + QName content does not match pattern facet. + QName 내용이 pattern 패싯과 일치하지 않습니다. + + + Notation content is not listed in the enumeration facet. + Notation 내용이 enumeration 패싯에 없습니다. + + + List content does not match length facet. + 목록 내용이 length 패싯과 일치하지 않습니다. + + + List content does not match minLength facet. + 목록 내용이 minLength 패싯과 일치하지 않습니다. + + + List content does not match maxLength facet. + 목록 내용이 maxLength 패싯과 일치하지 않습니다. + + + List content is not listed in the enumeration facet. + 목록 내용이 enumeration 패싯에 없습니다. + + + List content does not match pattern facet. + 목록 내용이 pattern 패싯과 일치하지 않습니다. + + + Union content is not listed in the enumeration facet. + 공용체 내용이 enumeration 패싯에 없습니다. + + + Union content does not match pattern facet. + 공용체 내용이 pattern 패싯과 일치하지 않습니다. + + + Data of type %1 are not allowed to be empty. + %1 형식 데이터는 비어 있으면 안 됩니다. + + + Element %1 is missing child element. + 원소 %1에 자식 원소가 없습니다. + + + There is one IDREF value with no corresponding ID: %1. + 대응하는 ID가 없는 IDREF 값이 있습니다: %1. + + + Loaded schema file is invalid. + 불러온 스키마 파일이 올바르지 않습니다. + + + %1 contains invalid data. + %1에 올바르지 않은 데이터가 있습니다. + + + xsi:schemaLocation namespace %1 has already appeared earlier in the instance document. + xsi:schemaLocation 네임스페이스 %1이(가) 인스턴스 문서의 더 위에 존재합니다. + + + xsi:noNamespaceSchemaLocation cannot appear after the first no-namespace element or attribute. + xsi:noNamespaceSchemaLocation은 첫 no-namespace 원소나 속성 다음에 나올 수 없습니다. + + + No schema defined for validation. + 검증할 스키마가 정의되지 않았습니다. + + + No definition for element %1 available. + 원소 %1의 정의를 사용할 수 없습니다. + + + Specified type %1 is not known to the schema. + 스키마에 지정한 형식 %1이(가) 정의되어 있지 않습니다. + + + Element %1 is not defined in this scope. + 원소 %1은(는) 이 범위에 정의되지 않았습니다. + + + Declaration for element %1 does not exist. + 원소 %1의 선언이 존재하지 않습니다. + + + Element %1 contains invalid content. + 원소 %1에 올바르지 않은 내용이 있습니다. + + + Element %1 is declared as abstract. + 원소 %1이 추상 원소로 선언되었습니다. + + + Element %1 is not nillable. + 원소 %1에 nil 값을 대입할 수 없습니다. + + + Attribute %1 contains invalid data: %2 + 속성 %1에 잘못된 데이터가 있음: %2 + + + Element contains content although it is nillable. + 원소에 nil 값을 할당할 수 있지만 내용이 들어 있습니다. + + + Fixed value constraint not allowed if element is nillable. + 원소에 nil 값을 대입할 수 있으면 고정된 값 제약 조건을 사용할 수 없습니다. + + + Specified type %1 is not validly substitutable with element type %2. + 지정한 형식 %1은(는) %2 형식의 원소로 올바르게 대체할 수 없습니다. + + + Complex type %1 is not allowed to be abstract. + 복합 형식 %1은(는) 추상으로 선언할 수 없습니다. + + + Element %1 contains not allowed attributes. + 원소 %1에 허용되지 않은 속성이 포함되어 있습니다. + + + Element %1 contains not allowed child element. + 원소 %1에 허용되지 않은 자식 원소가 포함되어 있습니다. + + + Content of element %1 does not match its type definition: %2. + 원소 %1의 내용은 형식 선언과 일치하지 않습니다: %2. + + + Content of element %1 does not match defined value constraint. + 원소 %1의 내용은 정의된 값 제약 조건과 일치하지 않습니다. + + + Element %1 contains not allowed child content. + 원소 %1에 허용되지 않은 자식 내용이 포함되어 있습니다. + + + Element %1 contains not allowed text content. + 원소 %1에 허용되지 않은 텍스트 내용이 포함되어 있습니다. + + + Element %1 cannot contain other elements, as it has a fixed content. + 원소 %1의 내용은 고정되어 있으므로 다른 원소를 포함할 수 없습니다. + + + Element %1 is missing required attribute %2. + 원소 %1에 필요한 속성 %2이(가) 없습니다. + + + Attribute %1 does not match the attribute wildcard. + 속성 %1이(가) 속성 와일드카드와 일치하지 않습니다. + + + Declaration for attribute %1 does not exist. + 속성 %1 선언이 존재하지 않습니다. + + + Element %1 contains two attributes of type %2. + 원소 %1은(는) 형식이 %2인 속성을 두 개 포함하고 있습니다. + + + Attribute %1 contains invalid content. + 속성 %1에 잘못된 데이터가 있습니다. + + + Element %1 contains unknown attribute %2. + 원소 %1에 알 수 없는 속성 %2이(가) 포함되어 있습니다. + + + Content of attribute %1 does not match its type definition: %2. + 속성 %1의 내용과 형식 정의가 일치하지 않습니다: %2. + + + Content of attribute %1 does not match defined value constraint. + 속성 %1의 내용이 정의된 값 제약 조건과 일치하지 않습니다. + + + Non-unique value found for constraint %1. + 제약 조건 %1에 중복되는 값이 있습니다. + + + Key constraint %1 contains absent fields. + 키 제약 조건 %1에 비어 있는 필드가 있습니다. + + + Key constraint %1 contains references nillable element %2. + 키 제약 조건 %1에서 nil 값이 올 수 있는 원소 %2을(를) 참조합니다. + + + No referenced value found for key reference %1. + 키 참조 %1에 대한 참조되는 값을 찾을 수 없습니다. + + + More than one value found for field %1. + 필드 %1에 하나 이상의 값이 있습니다. + + + Field %1 has no simple type. + 필드 %1에 간단한 형식이 없습니다. + + + ID value '%1' is not unique. + ID 값 '%1'이(가) 유일하지 않습니다. + + + '%1' attribute contains invalid QName content: %2. + 속성 '%1'에 올바르지 않은 QName 내용이 있음: %2. + + + empty + 비어 있음 + + + zero or one + 0이나 1 + + + exactly one + 정확히 1 + + + one or more + 1 이상 + + + zero or more + 0 이상 + + + Required type is %1, but %2 was found. + 요청한 형식은 %1(이)나 %2이(가) 요청되었습니다. + + + Promoting %1 to %2 may cause loss of precision. + %1을(를) %2(으)로 변환하면 정밀도를 잃어버릴 수 있습니다. + + + The focus is undefined. + 초점이 정의되지 않았습니다. + + + It's not possible to add attributes after any other kind of node. + 노드 뒤에 속성을 추가할 수 없습니다. + + + An attribute by name %1 has already been created. + 이름이 %1인 속성이 이미 생성되었습니다. + + + Only the Unicode Codepoint Collation is supported(%1). %2 is unsupported. + 유니코드 코드 포인트 순 정렬만 지원합니다(%1). %2은(는) 지원하지 않습니다. + + + diff --git a/translations/qtconfig_ko.ts b/translations/qtconfig_ko.ts new file mode 100644 index 0000000..9708a22 --- /dev/null +++ b/translations/qtconfig_ko.ts @@ -0,0 +1,745 @@ + + + + + MainWindow + + <p><b><font size+=2>Appearance</font></b></p><hr><p>Use this tab to customize the appearance of your Qt applications.</p><p>You can select the default GUI Style from the drop down list and customize the colors.</p><p>Any GUI Style plugins in your plugin path will automatically be added to the list of built-in Qt styles. (See the Library Paths tab for information on adding new plugin paths.)</p><p>When you choose 3-D Effects and Window Background colors, the Qt Configuration program will automatically generate a palette for you. To customize colors further, press the Tune Palette button to open the advanced palette editor.<p>The Preview Window shows what the selected Style and colors look like. + <p><b><font size+=2>모양</font></b></p><hr><p>이 탭을 사용하면 Qt 프로그램의 모양을 지정할 수 있습니다.</p><p>기본 GUI 스타일을 드롭 다운 목록에서 선택하고 색상을 사용자 정의할 수 있습니다.</p><p>플러그인 경로에 있는 GUI 스타일 플러그인이 Qt 내장 스타일과 더불어 추가될 것입니다. (새 플러그인 경로를 추가하려면 라이브러리 경로 탭을 참고하십시오.)</p><p>3차원 효과 및 창 배경색을 선택하면 Qt 설정 프로그램에서 자동으로 팔레트를 생성합니다. 색을 더 편집하려면 팔레트 조정 단추를 눌러서 고급 팔레트 편집기를 여십시오.<p>미리 보기 창에서 스타일과 색을 보여 줍니다. + + + <p><b><font size+=2>Fonts</font></b></p><hr><p>Use this tab to select the default font for your Qt applications. The selected font is shown (initially as 'Sample Text') in the line edit below the Family, Style and Point Size drop down lists.</p><p>Qt has a powerful font substitution feature that allows you to specify a list of substitute fonts. Substitute fonts are used when a font cannot be loaded, or if the specified font doesn't have a particular character.<p>For example, if you select the font Lucida, which doesn't have Korean characters, but need to show some Korean text using the Mincho font family you can do so by adding Mincho to the list. Once Mincho is added, any Korean characters that are not found in the Lucida font will be taken from the Mincho font. Because the font substitutions are lists, you can also select multiple families, such as Song Ti (for use with Chinese text). + <p><b><font size+=2>글꼴</font></b></p><hr><p>이 탭에서 Qt 프로그램의 글꼴을 설정할 수 있습니다. 선택한 글꼴은 글꼴 종류, 스타일, 포인트 크기 아래의 라인 편집기에 미리 보여집니다.(기본 텍스트는 '예제 텍스트')</p><p>Qt는 글꼴 대체 목록을 지정하는 기능을 갖추고 있습니다. 글꼴을 불러올 수 없거나 지정한 글꼴에 필요한 문자가 없는 경우 자동적으로 대체됩니다.<p>예를 들어 한글 글자가 없는 Lucida 글꼴을 선택한 경우, 한글을 명조체로 표시하고 싶다면 목록에 명조체를 추가하여 한글을 표시할 수 있습니다. 명조체를 추가하면 Lucida 글꼴에 없는 한글 글자는 명조체로 표시됩니다. 글꼴 대체는 목록으로 관리되므로, 중국어의 한자를 표시하고 싶은 경우에는 다른 글꼴을 추가할 수 있습니다. + + + <p><b><font size+=2>Interface</font></b></p><hr><p>Use this tab to customize the feel of your Qt applications.</p><p>If the Resolve Symlinks checkbox is checked Qt will follow symlinks when handling URLs. For example, in the file dialog, if this setting is turned on and /usr/tmp is a symlink to /var/tmp, entering the /usr/tmp directory will cause the file dialog to change to /var/tmp. With this setting turned off, symlinks are not resolved or followed.</p><p>The Global Strut setting is useful for people who require a minimum size for all widgets (e.g. when using a touch panel or for users who are visually impaired). Leaving the Global Strut width and height at 0 will disable the Global Strut feature</p><p>XIM (Extended Input Methods) are used for entering characters in languages that have large character sets, for example, Chinese and Japanese. + <p><b><font size+=2>인터페이스</font></b></p><hr><p>Qt 프로그램의 모습을 바꿀 수 있습니다.</p><p>심볼릭 링크 따라가기를 선택하면 Qt에서 URL을 처리할 때 심볼릭 링크를 따라갑니다. 예를 들어 이 설정이 활성화되어 있고 /usr/tmp가 /var/tmp를 향한 심볼릭 링크로 지정되어 있으면 /usr/tmp 디렉터리에 들어갔을 때 /var/tmp 디렉터리로 전환됩니다. 이 설정이 비활성화되어 있으면 심볼릭 링크를 따라가지 않습니다.</p><p>크기 제한 설정이 켜져 있으면 위젯의 최소 크기를 설정할 수 있습니다. 시각 장애가 있거나 터치 패널을 사용하는 등 최소 위젯 크기가 필요한 경우 사용할 수 있습니다. 크기 제한 설정을 0으로 설정하면 크기 제한 기능을 사용하지 않습니다.</p><p>XIM (X 입력기)는 한국어, 중국어, 일본어 등의 특수한 입력기를 사용하는 언어에 사용합니다. + + + <p><b><font size+=2>Printer</font></b></p><hr><p>Use this tab to configure the way Qt generates output for the printer.You can specify if Qt should try to embed fonts into its generated output.If you enable font embedding, the resulting postscript will be more portable and will more accurately reflect the visual output on the screen; however the resulting postscript file size will be bigger.<p>When using font embedding you can select additional directories where Qt should search for embeddable font files. By default, the X server font path is used. + <p><b><font size+=2>프린터</font></b></p><hr><p>Qt에서 프린터를 다루는 방식을 설정할 수 있습니다. Qt에서 생성한 출력물에 글꼴을 임베딩할 지 결정할 수 있습니다. 만약 글꼴 임베딩을 사용하면 생성된 포스트스크립트 파일은 지정한 글꼴이 없는 곳에서도 똑같이 출력할 수 있으나, 파일의 크기가 더 커집니다.<p>글꼴 임베딩을 사용하는 경우 Qt가 글꼴 파일을 찾을 추가 디렉터리를 설정할 수 있습니다. 기본적으로 X 글꼴 경로를 사용합니다. + + + <p><b><font size+=2>Phonon</font></b></p><hr><p>Use this tab to configure the Phonon GStreamer multimedia backend. <p>It is reccommended to leave all settings on "Auto" to let Phonon determine your settings automatically. + <p><b><font size+=2>Phonon</font></b></p><hr><p>이 탭을 사용하면 Phonon GStreamer 멀티미디어 백엔드를 설정할 수 있습니다.<p>모든 설정을 "자동"으로 설정하여 Phonon에서 자동으로 설정하도록 하는 것을 추천합니다. + + + Desktop Settings (Default) + 데스크톱 설정 (기본값) + + + Choose style and palette based on your desktop settings. + 데스크톱 설정을 기반으로 한 스타일과 팔레트를 선택하십시오. + + + On The Spot + On The Spot + + + Auto (default) + 자동 (기본값) + + + Choose audio output automatically. + 자동으로 오디오 출력을 선택합니다. + + + aRts + aRts + + + Experimental aRts support for GStreamer. + GStreamer의 실험적인 aRts 출력입니다. + + + Phonon GStreamer backend not available. + Phonon GStreamer 백엔드를 사용할 수 없습니다. + + + Choose render method automatically + 렌더링 방식 자동으로 선택하기 + + + X11 + X11 + + + Use X11 Overlays + X11 오버레이 사용하기 + + + OpenGL + OpenGL + + + Use OpenGL if available + 사용 가능한 경우 OpenGL 사용하기 + + + Software + 소프트웨어 + + + Use simple software rendering + 간단한 소프트웨어 렌더링 사용하기 + + + No changes to be saved. + 저장할 변경 사항이 없습니다. + + + Saving changes... + 변경 사항 저장하는 중... + + + Over The Spot + Over The Spot + + + Off The Spot + Off The Spot + + + Root + 루트 + + + Select a Directory + 디렉터리 선택 + + + <h3>%1</h3><br/>Version %2<br/><br/>Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + <h3>%1</h3><br/>버전 %2<br/><br/>저작권자 (C) 2010 Nokia Corporation and/or its subsidiary(-ies). + + + Qt Configuration + Qt 설정 + + + Save Changes + 변경 사항 저장 + + + Save changes to settings? + 변경 사항을 저장하시겠습니까? + + + &Yes + 예(&Y) + + + &No + 아니오(&N) + + + &Cancel + 취소(&C) + + + + MainWindowBase + + Qt Configuration + Qt 설정 + + + Appearance + 모양 + + + GUI Style + GUI 스타일 + + + Select GUI &Style: + GUI 스타일 선택(&S): + + + Preview + 미리 보기 + + + Select &Palette: + 팔레트 선택(&P): + + + Active Palette + 활성 팔레트 + + + Inactive Palette + 비활성 팔레트 + + + Disabled Palette + 사용 불가 팔레트 + + + Build Palette + 팔레트 생성 + + + &3-D Effects: + 3차원 효과(&3): + + + Window Back&ground: + 창 배경(&G): + + + &Tune Palette... + 팔레트 조정(&T)... + + + Please use the KDE Control Center to set the palette. + KDE 제어판에서 팔레트를 조정하십시오. + + + Fonts + 글꼴 + + + Default Font + 기본 글꼴 + + + &Style: + 스타일(&S): + + + &Point Size: + 포인트 크기(&P): + + + F&amily: + 종류(&A): + + + Sample Text + 견본 텍스트 + + + Font Substitution + 글꼴 대체 + + + S&elect or Enter a Family: + 글꼴을 선택하거나 입력하십시오(&E): + + + Current Substitutions: + 현재 대체 목록: + + + Up + 위로 + + + Down + 아래로 + + + Remove + 삭제 + + + Select s&ubstitute Family: + 대체할 글꼴을 선택하십시오(&U): + + + Add + 추가 + + + Interface + 인터페이스 + + + Feel Settings + 모양 설정 + + + ms + ms + + + &Double Click Interval: + 두 번 누름 간격(&D): + + + No blinking + 깜빡임 없음 + + + &Cursor Flash Time: + 커서 깜빡임 시간(&C): + + + lines + + + + Wheel &Scroll Lines: + 휠 스크롤 줄 수(&S): + + + Resolve symlinks in URLs + URL의 심볼릭 링크 따라가기 + + + GUI Effects + GUI 효과 + + + &Enable + 활성화(&E) + + + Alt+E + Alt+E + + + &Menu Effect: + 메뉴 효과(&M): + + + C&omboBox Effect: + 콤보 상자 효과(&O): + + + &ToolTip Effect: + 풍선 도움말 효과(&T): + + + Tool&Box Effect: + 도구 상자 효과(&B): + + + Disable + 사용 안함 + + + Animate + 애니메이션 + + + Fade + 페이드 + + + Global Strut + 크기 제한 + + + Minimum &Width: + 최소 폭(&W): + + + Minimum Hei&ght: + 최소 높이(&G): + + + pixels + 픽셀 + + + Enhanced support for languages written right-to-left + 오른쪽에서 왼쪽으로 쓰는 언어 지원 향상 + + + XIM Input Style: + XIM 입력 방식: + + + On The Spot + On The Spot + + + Over The Spot + Over The Spot + + + Off The Spot + Off The Spot + + + Root + 루트 + + + Default Input Method: + 기본 입력기: + + + Printer + 프린터 + + + Enable Font embedding + 글꼴 임베딩 사용하기 + + + Font Paths + 글꼴 경로 + + + Browse... + 찾아보기... + + + Press the <b>Browse</b> button or enter a directory and press Enter to add them to the list. + <b>찾아보기</b> 단추를 누르거나 디렉터리를 입력하고 Enter 키를 눌러서 목록에 추가할 수 있습니다. + + + Phonon + Phonon + + + About Phonon + Phonon 정보 + + + Current Version: + 현재 버전: + + + Not available + 사용할 수 없음 + + + Website: + 웹 사이트: + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://phonon.kde.org"><span style=" text-decoration: underline; color:#0000ff;">http://phonon.kde.org</span></a></p></body></html> + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://phonon.kde.org"><span style=" text-decoration: underline; color:#0000ff;">http://phonon.kde.org</span></a></p></body></html> + + + About GStreamer + GStreamer 정보 + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://gstreamer.freedesktop.org/"><span style=" text-decoration: underline; color:#0000ff;">http://gstreamer.freedesktop.org/</span></a></p></body></html> + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="http://gstreamer.freedesktop.org/"><span style=" text-decoration: underline; color:#0000ff;">http://gstreamer.freedesktop.org/</span></a></p></body></html> + + + GStreamer backend settings + GStreamer 백엔드 설정 + + + Preferred audio sink: + 선호하는 오디오 싱크: + + + Preferred render method: + 선호하는 렌더링 방법: + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">Note: changes to these settings may prevent applications from starting up correctly.</span></p></body></html> + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-style:italic;">메모: 이 설정을 변경하면 프로그램이 시작되지 않을 수도 있습니다.</span></p></body></html> + + + &File + 파일(&F) + + + &Help + 도움말(&H) + + + &Save + 저장(&S) + + + Save + 저장 + + + Ctrl+S + Ctrl+S + + + E&xit + 끝내기(&X) + + + Exit + 끝내기 + + + &About + 정보(&A) + + + About + 정보 + + + About &Qt + Qt 정보(&Q) + + + About Qt + Qt 정보 + + + + PaletteEditorAdvancedBase + + Tune Palette + 팔레트 조정 + + + <b>Edit Palette</b><p>Change the palette of the current widget or form.</p><p>Use a generated palette or select colors for each color group and each color role.</p><p>The palette can be tested with different widget layouts in the preview section.</p> + <b>팔레트 조정</b><p>현재 위젯이나 폼의 팔레트를 변경합니다.</p><p>생성된 팔레트를 사용하거나, 각각 색상 그룹과 역할의 색을 선택하십시오.</p><p>미리 보기 섹션의 여러 위젯 레이아웃으로 팔레트를 테스트할 수 있습니다.</p> + + + Select &Palette: + 팔레트 선택(&P): + + + Active Palette + 활성 팔레트 + + + Inactive Palette + 비활성 팔레트 + + + Disabled Palette + 사용 불가 팔레트 + + + Auto + 자동 + + + Build inactive palette from active + 활성 팔레트에서 비활성 팔레트 생성 + + + Build disabled palette from active + 활성 팔레트에서 사용 불가 팔레트 생성 + + + Central color &roles + 중심 색상 역할(&R) + + + Choose central color role + 중심 색상 역할 선택 + + + <b>Select a color role.</b><p>Available central roles are: <ul> <li>Window - general background color.</li> <li>WindowText - general foreground color. </li> <li>Base - used as background color for e.g. text entry widgets, usually white or another light color. </li> <li>Text - the foreground color used with Base. Usually this is the same as WindowText, in what case it must provide good contrast both with Window and Base. </li> <li>Button - general button background color, where buttons need a background different from Window, as in the Macintosh style. </li> <li>ButtonText - a foreground color used with the Button color. </li> <li>Highlight - a color to indicate a selected or highlighted item. </li> <li>HighlightedText - a text color that contrasts to Highlight. </li> <li>BrightText - a text color that is very different from WindowText and contrasts well with e.g. black. </li> </ul> </p> + <b>색상 역할을 선택하십시오.</b><p>사용 가능한 색상 역할 목록: <ul> <li>창 - 일반적인 배경색.</li> <li>창 텍스트 - 일반적인 전경색. </li> <li>기본 - 텍스트 입력 위젯과 같은 곳의 배경색. 일반적으로 흰색 또는 밝은 색입니다.</li> <li>텍스트 - '기본'과 같이 사용되는 전경색입니다. 대개 창 텍스트와 같은 색을 사용합니다.</li> <li>단추 - 일반적인 단추 배경색. 매킨토시 스타일과 같이 단추와 창의 배경색이 다른 곳에서 사용합니다.</li> <li>단추 텍스트 - 단추 색과 같이 사용되는 전경색.</li> <li>강조 - 선택하거나 강조된 항목을 나타내는 색.</li> <li>강조 텍스트 - '강조'와 같이 사용되는 텍스트 색.</li> <li>밝은 텍스트 - 창 텍스트와 대조되는 텍스트 색. 예를 들어 검정색입니다.</li> </ul> </p> + + + Window + + + + WindowText + 창 텍스트 + + + Button + 단추 + + + Base + 기본 + + + Text + 텍스트 + + + BrightText + 밝은 텍스트 + + + ButtonText + 단추 텍스트 + + + Highlight + 강조 + + + HighlightedText + 강조된 텍스트 + + + &Select Color: + 색 선택(&S): + + + Choose a color + 색 선택 + + + Choose a color for the selected central color role. + 중심 색상 역할에 사용할 색상을 선택하십시오. + + + 3-D shadow &effects + 3차원 그림자 효과(&E) + + + Build &from button color + 단추 색상에서 생성(&F) + + + Generate shadings + 그림자 생성 + + + Check to let 3D-effect colors be calculated from button-color. + 3차원 효과 색상을 단추 색상에서 생성하려면 누르십시오. + + + Choose 3D-effect color role + 3차원 효과 색상 역할 선택 + + + <b>Select a color role.</b><p>Available effect roles are: <ul> <li>Light - lighter than Button color. </li> <li>Midlight - between Button and Light. </li> <li>Mid - between Button and Dark. </li> <li>Dark - darker than Button. </li> <li>Shadow - a very dark color. </li> </ul> + <b>색상 역할을 선택하십시오.</b><p>사용 가능한 색상 역할 목록: <ul> <li>밝음 - 단추 색보다 밝음. </li> <li>약간 밝음 - '밝음'과 '단추 색'의 중간.</li> <li>중간 - '단추 색'과 '어두움'의 중간.</li> <li>어두움 - 단추 색보다 어두움.</li> <li>그림자 - 매우 어두운 색.</li> </ul> + + + Light + 밝음 + + + Midlight + 약간 밝음 + + + Mid + 중간 + + + Dark + 어두움 + + + Shadow + 그림자 + + + Select Co&lor: + 색 선택(&L): + + + Choose a color for the selected effect color role. + 선택한 효과 색상 역할에 사용할 색을 선택하십시오. + + + OK + 확인 + + + Close dialog and apply all changes. + 대화 상자를 닫고 변경 사항을 적용합니다. + + + Cancel + 취소 + + + Close dialog and discard all changes. + 대화 상자를 닫고 변경 사항을 적용하지 않습니다. + + + + PreviewFrame + + Desktop settings will only take effect after an application restart. + 데스크톱 설정은 프로그램을 다시 시작해야 적용됩니다. + + + + PreviewWidgetBase + + Preview Window + 미리 보기 창 + + + ButtonGroup + 단추 그룹 + + + RadioButton1 + 라디오 단추 1 + + + RadioButton2 + 라디오 단추 2 + + + RadioButton3 + 라디오 단추 3 + + + ButtonGroup2 + 단추 그룹 2 + + + CheckBox1 + 체크 상자 1 + + + CheckBox2 + 체크 상자 2 + + + LineEdit + 라인 편집기 + + + ComboBox + 콤보 상자 + + + PushButton + 누름 단추 + + + <p> +<a href="http://qt.nokia.com">http://qt.nokia.com</a> +</p> +<p> +<a href="http://www.kde.org">http://www.kde.org</a> +</p> + <p> +<a href="http://qt.nokia.com">http://qt.nokia.com</a> +</p> +<p> +<a href="http://www.kde.org">http://www.kde.org</a> +</p> + + + diff --git a/translations/qvfb_ko.ts b/translations/qvfb_ko.ts new file mode 100644 index 0000000..3d34090 --- /dev/null +++ b/translations/qvfb_ko.ts @@ -0,0 +1,415 @@ + + + + + AnimationSaveWidget + + Record + 녹화 + + + Reset + 초기화 + + + Save + 저장 + + + Save in MPEG format (requires netpbm package installed) + MPEG로 저장 (netpbm 패키지가 필요함) + + + Click record to begin recording. + 녹화를 누르면 녹화를 시작합니다. + + + Finished saving. + 저장하였습니다. + + + Paused. Click record to resume, or save if done. + 일시 정지됨. 녹화 단추를 누르면 다시 시작하며, 끝났으면 저장하십시오. + + + Pause + 일시 정지 + + + Recording... + 녹화 중... + + + Saving... + 저장 중... + + + Save animation... + 애니메이션 저장 중... + + + Save canceled. + 저장이 취소되었습니다. + + + Save failed! + 저장에 실패하였습니다! + + + + Config + + Configure + 설정 + + + Size + 크기 + + + 176x220 "SmartPhone" + 176x220 "스마트폰" + + + 240x320 "PDA" + 240x320 "PDA" + + + 320x240 "TV" / "QVGA" + 320x240 "TV" / "QVGA" + + + 640x480 "VGA" + 640x480 "VGA" + + + 800x480 + 800x480 + + + 800x600 + 800x600 + + + 1024x768 + 1024x768 + + + Custom + 사용자 정의 + + + Depth + 색 농도 + + + 1 bit monochrome + 1비트 단색 + + + 2 bit grayscale + 2비트 그레이스케일 + + + 4 bit grayscale + 4비트 그레이스케일 + + + 8 bit + 8비트 + + + 12 (16) bit + 12(16)비트 + + + 15 bit + 15비트 + + + 16 bit + 16비트 + + + 18 bit + 18비트 + + + 24 bit + 24비트 + + + 32 bit + 32비트 + + + 32 bit ARGB + 32비트 ARGB + + + Swap red and blue channels + 빨간색과 파란색 채널 바꾸기 + + + BGR format + BGR 형식 + + + Skin + 스킨 + + + None + 없음 + + + Emulate touch screen (no mouse move) + 터치스크린 흉내내기 (마우스 이동 없음) + + + Emulate LCD screen (Only with fixed zoom of 3.0 times magnification) + LCD 스크린 흉내내기 (3배 확대로 고정됨) + + + <p>Note that any applications using the virtual framebuffer will be terminated if you change the Size or Depth <i>above</i>. You may freely modify the Gamma <i>below</i>. + <p><i>위</i>에 있는 크기나 색 농도 설정을 바꾸면 가상 프레임버퍼를 사용하는 프로그램이 종료됩니다. <i>아래</i>에 있는 감마 설정은 영향을 받지 않습니다. + + + Gamma + 감마 + + + Blue + 파란색 + + + 1.0 + 1.0 + + + Green + 녹색 + + + All + 모두 + + + Red + 빨간색 + + + Set all to 1.0 + 모두 1.0으로 설정 + + + &OK + 확인(&O) + + + &Cancel + 취소(&C) + + + + DeviceSkin + + The image file '%1' could not be loaded. + 그림 파일 '%1'을(를) 불러올 수 없습니다. + + + The skin directory '%1' does not contain a configuration file. + 스킨 디렉터리 '%1'에 설정 파일이 없습니다. + + + The skin configuration file '%1' could not be opened. + 스킨 설정 파일 '%1'을(를) 열 수 없습니다. + + + The skin configuration file '%1' could not be read: %2 + 스킨 설정 파일 '%1'을(를) 읽을 수 없습니다: %2 + + + Syntax error: %1 + 문법 오류: %1 + + + The skin "up" image file '%1' does not exist. + 스킨 "up" 그림 파일 '%1'이(가) 존재하지 않습니다. + + + The skin "down" image file '%1' does not exist. + 스킨 "down" 그림 파일 '%1'이(가) 존재하지 않습니다. + + + The skin "closed" image file '%1' does not exist. + 스킨 "closed" 그림 파일 '%1'이(가) 존재하지 않습니다. + + + The skin cursor image file '%1' does not exist. + 스킨 커서 그림 파일 '%1'이(가) 존재하지 않습니다. + + + Syntax error in area definition: %1 + 영역 지정 문법 오류: %1 + + + Mismatch in number of areas, expected %1, got %2. + 영역 개수 오류가 일치하지 않음. %1개를 예상하였으나 %2개가 들어옴. + + + + QVFb + + &File + 파일(&F) + + + &Configure... + 설정(&C)... + + + &Save image... + 그림 저장(&S)... + + + &Animation... + 애니메이션(&A)... + + + &Quit + 끝내기(&Q) + + + &View + 보기(&V) + + + Show &Cursor + 커서 보이기(&C) + + + &Refresh Rate... + 갱신 주기(&R)... + + + &No rotation + 회전 없음(&N) + + + &90° rotation + 90° 회전(&9) + + + 1&80° rotation + 180° 회전(&8) + + + 2&70° rotation + 270° 회전(&7) + + + Zoom scale &0.5 + 0.5배로 축소(&0) + + + Zoom scale 0.7&5 + 0.75배로 축소 (&5) + + + Zoom scale &1 + 1배로 크기 조정 (&1) + + + Zoom scale &2 + 2배로 확대(&2) + + + Zoom scale &3 + 3배로 확대(&3) + + + Zoom scale &4 + 4배로 확대(&4) + + + Zoom &scale... + 크기 조정(&S)... + + + &Help + 도움말(&H) + + + &About... + 정보(&A)... + + + Save Main Screen image + 주 화면 그림 저장 + + + snapshot.png + snapshot.png + + + Portable Network Graphics (*.png) + Portable Network Graphics (*.png) + + + Save Main Screen Image + 주 화면 그림 저장 + + + Save failed. Check that you have permission to write to the target directory. + 저장하는 데 실패하였습니다. 대상 디렉터리에 쓰기 권한이 있는지 확인하십시오. + + + Save Second Screen image + 두 번째 화면 그림 저장 + + + Save Second Screen Image + 두 번째 화면 그림 저장 + + + About QVFB + QVFB 정보 + + + <h2>The Qt for Embedded Linux Virtual X11 Framebuffer</h2><p>This application runs under Qt for X11, emulating a simple framebuffer, which the Qt for Embedded Linux server and clients can attach to just as if it was a hardware Linux framebuffer. <p>With the aid of this development tool, you can develop Qt for Embedded Linux applications under X11 without having to switch to a virtual console. This means you can comfortably use your other development tools such as GUI profilers and debuggers. + <h2>Qt for Embedded Linux 가상 X11 프레임버퍼</h2><p>이 프로그램은 Qt for X11 하에서 실행되며, Qt for Embedded Linux 서버 및 클라이언트가 하드웨어 리눅스 프레임버퍼처럼 사용할 수 있습니다.<p>이 도구를 사용하면 Qt for Embedded Linux 프로그램을 가상 콘솔 전환 없이 X11에서 개발할 수 있으며, GUI 프로파일러나 디버거를 사용할 수 있습니다. + + + Browse... + 찾아보기... + + + Load Custom Skin... + 사용자 정의 스킨 불러오기... + + + All QVFB Skins (*.skin) + 모든 QVFB 스킨 (*.skin) + + + + QVFbRateDialog + + Target frame rate: + 대상 프레임 레이트: + + + %1fps + %1fps + + + OK + 확인 + + + Cancel + 취소 + + + -- cgit v0.12 From db6f36b05e83b0009a00170cab6672b81059977e Mon Sep 17 00:00:00 2001 From: Oswald Buddenhagen Date: Wed, 20 Apr 2011 18:54:28 +0200 Subject: remove exec bit ... again ... --- translations/assistant_cs.ts | 0 translations/designer_cs.ts | 0 translations/linguist_cs.ts | 0 translations/qt_cs.ts | 0 translations/qt_help_cs.ts | 0 5 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 translations/assistant_cs.ts mode change 100755 => 100644 translations/designer_cs.ts mode change 100755 => 100644 translations/linguist_cs.ts mode change 100755 => 100644 translations/qt_cs.ts mode change 100755 => 100644 translations/qt_help_cs.ts diff --git a/translations/assistant_cs.ts b/translations/assistant_cs.ts old mode 100755 new mode 100644 diff --git a/translations/designer_cs.ts b/translations/designer_cs.ts old mode 100755 new mode 100644 diff --git a/translations/linguist_cs.ts b/translations/linguist_cs.ts old mode 100755 new mode 100644 diff --git a/translations/qt_cs.ts b/translations/qt_cs.ts old mode 100755 new mode 100644 diff --git a/translations/qt_help_cs.ts b/translations/qt_help_cs.ts old mode 100755 new mode 100644 -- cgit v0.12 From 6e5a642c9484536fc173714f560f739944368cf5 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Thu, 21 Apr 2011 14:15:38 +1000 Subject: Elide has unexpected effect on Text's implicitWidth The elided string was used to calculate the implicitWidth rather than the full string. Change-Id: I51b8800b47d4e32f4d5eef07c71df10e2df905b7 Task-number: QTBUG-18627 Reviewed-by: Michael Brasser --- src/declarative/graphicsitems/qdeclarativetext.cpp | 23 +++++++++++++++++----- .../graphicsitems/qdeclarativetext_p_p.h | 1 + .../qdeclarativetext/data/elideimplicitwidth.qml | 7 +++++++ .../qdeclarativetext/tst_qdeclarativetext.cpp | 7 +++++++ 4 files changed, 33 insertions(+), 5 deletions(-) create mode 100644 tests/auto/declarative/qdeclarativetext/data/elideimplicitwidth.qml diff --git a/src/declarative/graphicsitems/qdeclarativetext.cpp b/src/declarative/graphicsitems/qdeclarativetext.cpp index 720692c..1d51840 100644 --- a/src/declarative/graphicsitems/qdeclarativetext.cpp +++ b/src/declarative/graphicsitems/qdeclarativetext.cpp @@ -101,7 +101,8 @@ QDeclarativeTextPrivate::QDeclarativeTextPrivate() format(QDeclarativeText::AutoText), wrapMode(QDeclarativeText::NoWrap), lineHeight(1), lineHeightMode(QDeclarativeText::ProportionalHeight), lineCount(1), truncated(false), maximumLineCount(INT_MAX), maximumLineCountValid(false), imageCacheDirty(true), updateOnComponentComplete(true), richText(false), singleline(false), - cacheAllTextAsImage(true), internalWidthUpdate(false), requireImplicitWidth(false), hAlignImplicit(true), rightToLeftText(false), naturalWidth(0), doc(0) + cacheAllTextAsImage(true), internalWidthUpdate(false), requireImplicitWidth(false), hAlignImplicit(true), + rightToLeftText(false), layoutTextElided(false), naturalWidth(0), doc(0) { cacheAllTextAsImage = enableImageCache(); QGraphicsItemPrivate::acceptedMouseButtons = Qt::LeftButton; @@ -217,6 +218,7 @@ void QDeclarativeTextPrivate::updateLayout() return; } + layoutTextElided = false; // Setup instance of QTextLayout for all cases other than richtext if (!richText) { layout.clearLayout(); @@ -227,10 +229,13 @@ void QDeclarativeTextPrivate::updateLayout() singleline = !tmp.contains(QChar::LineSeparator); if (singleline && !maximumLineCountValid && elideMode != QDeclarativeText::ElideNone && q->widthValid()) { QFontMetrics fm(font); - tmp = fm.elidedText(tmp,(Qt::TextElideMode)elideMode,q->width()); // XXX still worth layout...? - if (tmp != text && !truncated) { - truncated = true; - emit q->truncatedChanged(); + tmp = fm.elidedText(tmp,(Qt::TextElideMode)elideMode,q->width()); + if (tmp != text) { + layoutTextElided = true; + if (!truncated) { + truncated = true; + emit q->truncatedChanged(); + } } } layout.setText(tmp); @@ -377,6 +382,12 @@ QRect QDeclarativeTextPrivate::setupTextLayout() if (requireImplicitWidth && q->widthValid()) { // requires an extra layout + QString elidedText; + if (layoutTextElided) { + // We have provided elided text to the layout, but we must calculate unelided width. + elidedText = layout.text(); + layout.setText(text); + } layout.beginLayout(); forever { QTextLine line = layout.createLine(); @@ -390,6 +401,8 @@ QRect QDeclarativeTextPrivate::setupTextLayout() br = br.united(line.naturalTextRect()); } naturalWidth = br.width(); + if (layoutTextElided) + layout.setText(elidedText); } if (maximumLineCountValid) { diff --git a/src/declarative/graphicsitems/qdeclarativetext_p_p.h b/src/declarative/graphicsitems/qdeclarativetext_p_p.h index e3ab62a..6a3d581 100644 --- a/src/declarative/graphicsitems/qdeclarativetext_p_p.h +++ b/src/declarative/graphicsitems/qdeclarativetext_p_p.h @@ -116,6 +116,7 @@ public: bool requireImplicitWidth:1; bool hAlignImplicit:1; bool rightToLeftText:1; + bool layoutTextElided:1; QRect layedOutTextRect; QSize paintedSize; diff --git a/tests/auto/declarative/qdeclarativetext/data/elideimplicitwidth.qml b/tests/auto/declarative/qdeclarativetext/data/elideimplicitwidth.qml new file mode 100644 index 0000000..60ae15c --- /dev/null +++ b/tests/auto/declarative/qdeclarativetext/data/elideimplicitwidth.qml @@ -0,0 +1,7 @@ +import QtQuick 1.1 + +Text { + text: "Hello World" + elide: Text.ElideRight + width: 30 +} diff --git a/tests/auto/declarative/qdeclarativetext/tst_qdeclarativetext.cpp b/tests/auto/declarative/qdeclarativetext/tst_qdeclarativetext.cpp index ca6e87a..82b6f73 100644 --- a/tests/auto/declarative/qdeclarativetext/tst_qdeclarativetext.cpp +++ b/tests/auto/declarative/qdeclarativetext/tst_qdeclarativetext.cpp @@ -390,6 +390,13 @@ void tst_qdeclarativetext::elide() QCOMPARE(textObject->width(), 100.); } } + + // QTBUG-18627 + QUrl qmlfile = QUrl::fromLocalFile(SRCDIR "/data/elideimplicitwidth.qml"); + QDeclarativeComponent textComponent(&engine, qmlfile); + QDeclarativeItem *item = qobject_cast(textComponent.create()); + QVERIFY(item != 0); + QVERIFY(item->implicitWidth() > item->width()); } void tst_qdeclarativetext::textFormat() -- cgit v0.12 From 2f173e4945dd8414636c1061acfaf9c2d8b718d8 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Tue, 19 Apr 2011 14:00:48 +1000 Subject: Fix TextInput echoMode clearing inputMethodHints set by the user. Changing to the Normal echo mode from another mode clears the NoPredictiveText and NoAutoUppercase flags, irrespective of who originally set them. Add separate accessors for the property value so echo mode can overwrite the authoritive value without losing the value set in QML. Change-Id: I6a9563057bb17796b17ac7c2a3c564bb5e886c4d Task-number: QTBUG-18735 Reviewed-by: Martin Jones --- .../graphicsitems/qdeclarativetextinput.cpp | 40 +++++++++++++++------ .../graphicsitems/qdeclarativetextinput_p.h | 5 ++- .../graphicsitems/qdeclarativetextinput_p_p.h | 4 ++- .../tst_qdeclarativetextinput.cpp | 42 +++++++++++++++++++++- 4 files changed, 78 insertions(+), 13 deletions(-) diff --git a/src/declarative/graphicsitems/qdeclarativetextinput.cpp b/src/declarative/graphicsitems/qdeclarativetextinput.cpp index e1c2107..ee241d6 100644 --- a/src/declarative/graphicsitems/qdeclarativetextinput.cpp +++ b/src/declarative/graphicsitems/qdeclarativetextinput.cpp @@ -862,6 +862,20 @@ bool QDeclarativeTextInput::hasAcceptableInput() const state. */ +void QDeclarativeTextInputPrivate::updateInputMethodHints() +{ + Q_Q(QDeclarativeTextInput); + Qt::InputMethodHints hints = inputMethodHints; + uint echo = control->echoMode(); + if (echo == QDeclarativeTextInput::Password || echo == QDeclarativeTextInput::NoEcho) + hints |= Qt::ImhHiddenText; + else if (echo == QDeclarativeTextInput::PasswordEchoOnEdit) + hints &= ~Qt::ImhHiddenText; + if (echo != QDeclarativeTextInput::Normal) + hints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText); + q->setInputMethodHints(hints); +} + /*! \qmlproperty enumeration TextInput::echoMode @@ -884,21 +898,27 @@ void QDeclarativeTextInput::setEchoMode(QDeclarativeTextInput::EchoMode echo) Q_D(QDeclarativeTextInput); if (echoMode() == echo) return; - Qt::InputMethodHints imHints = inputMethodHints(); - if (echo == Password || echo == NoEcho) - imHints |= Qt::ImhHiddenText; - else - imHints &= ~Qt::ImhHiddenText; - if (echo != Normal) - imHints |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText); - else - imHints &= ~(Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText); - setInputMethodHints(imHints); d->control->setEchoMode((uint)echo); + d->updateInputMethodHints(); q_textChanged(); emit echoModeChanged(echoMode()); } +Qt::InputMethodHints QDeclarativeTextInput::imHints() const +{ + Q_D(const QDeclarativeTextInput); + return d->inputMethodHints; +} + +void QDeclarativeTextInput::setIMHints(Qt::InputMethodHints hints) +{ + Q_D(QDeclarativeTextInput); + if (d->inputMethodHints == hints) + return; + d->inputMethodHints = hints; + d->updateInputMethodHints(); +} + /*! \qmlproperty Component TextInput::cursorDelegate The delegate for the cursor in the TextInput. diff --git a/src/declarative/graphicsitems/qdeclarativetextinput_p.h b/src/declarative/graphicsitems/qdeclarativetextinput_p.h index 8c873b3..ec70e43 100644 --- a/src/declarative/graphicsitems/qdeclarativetextinput_p.h +++ b/src/declarative/graphicsitems/qdeclarativetextinput_p.h @@ -86,7 +86,7 @@ class Q_AUTOTEST_EXPORT QDeclarativeTextInput : public QDeclarativeImplicitSizeP Q_PROPERTY(QValidator* validator READ validator WRITE setValidator NOTIFY validatorChanged) #endif Q_PROPERTY(QString inputMask READ inputMask WRITE setInputMask NOTIFY inputMaskChanged) - Q_PROPERTY(Qt::InputMethodHints inputMethodHints READ inputMethodHints WRITE setInputMethodHints) + Q_PROPERTY(Qt::InputMethodHints inputMethodHints READ imHints WRITE setIMHints) Q_PROPERTY(bool acceptableInput READ hasAcceptableInput NOTIFY acceptableInputChanged) Q_PROPERTY(EchoMode echoMode READ echoMode WRITE setEchoMode NOTIFY echoModeChanged) @@ -215,6 +215,9 @@ public: bool isInputMethodComposing() const; + Qt::InputMethodHints imHints() const; + void setIMHints(Qt::InputMethodHints hints); + Q_SIGNALS: void textChanged(); void cursorPositionChanged(); diff --git a/src/declarative/graphicsitems/qdeclarativetextinput_p_p.h b/src/declarative/graphicsitems/qdeclarativetextinput_p_p.h index fd4da2e..ed53e8f 100644 --- a/src/declarative/graphicsitems/qdeclarativetextinput_p_p.h +++ b/src/declarative/graphicsitems/qdeclarativetextinput_p_p.h @@ -73,7 +73,7 @@ public: QDeclarativeTextInputPrivate() : control(new QLineControl(QString())), color((QRgb)0), style(QDeclarativeText::Normal), styleColor((QRgb)0), hAlign(QDeclarativeTextInput::AlignLeft), - mouseSelectionMode(QDeclarativeTextInput::SelectCharacters), + mouseSelectionMode(QDeclarativeTextInput::SelectCharacters), inputMethodHints(Qt::ImhNone), hscroll(0), oldScroll(0), oldValidity(false), focused(false), focusOnPress(true), showInputPanelOnFocus(true), clickCausedFocus(false), cursorVisible(false), autoScroll(true), selectByMouse(false), canPaste(false), hAlignImplicit(true) @@ -108,6 +108,7 @@ public: void mirrorChange(); int calculateTextWidth(); bool sendMouseEventToInputContext(QGraphicsSceneMouseEvent *event, QEvent::Type eventType); + void updateInputMethodHints(); QLineControl* control; @@ -120,6 +121,7 @@ public: QColor styleColor; QDeclarativeTextInput::HAlignment hAlign; QDeclarativeTextInput::SelectionMode mouseSelectionMode; + Qt::InputMethodHints inputMethodHints; QPointer cursorComponent; QPointer cursorItem; QPointF pressPos; diff --git a/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp b/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp index 943b1fa..79d95d3 100644 --- a/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp +++ b/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp @@ -1364,8 +1364,10 @@ void tst_qdeclarativetextinput::inputMethods() QVERIFY(canvas->rootObject() != 0); QDeclarativeTextInput *input = qobject_cast(canvas->rootObject()); QVERIFY(input != 0); + QVERIFY(input->imHints() & Qt::ImhNoPredictiveText); QVERIFY(input->inputMethodHints() & Qt::ImhNoPredictiveText); - input->setInputMethodHints(Qt::ImhUppercaseOnly); + input->setIMHints(Qt::ImhUppercaseOnly); + QVERIFY(input->imHints() & Qt::ImhUppercaseOnly); QVERIFY(input->inputMethodHints() & Qt::ImhUppercaseOnly); QVERIFY(canvas->rootObject() != 0); @@ -1805,6 +1807,7 @@ void tst_qdeclarativetextinput::echoMode() ref &= ~Qt::ImhHiddenText; ref &= ~(Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText); QCOMPARE(input->inputMethodHints(), ref); + QCOMPARE(input->imHints(), Qt::ImhNone); input->setEchoMode(QDeclarativeTextInput::NoEcho); QCOMPARE(input->text(), initial); QCOMPARE(input->displayText(), QLatin1String("")); @@ -1813,6 +1816,7 @@ void tst_qdeclarativetextinput::echoMode() ref |= Qt::ImhHiddenText; ref |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText); QCOMPARE(input->inputMethodHints(), ref); + QCOMPARE(input->imHints(), Qt::ImhNone); input->setEchoMode(QDeclarativeTextInput::Password); //Password ref |= Qt::ImhHiddenText; @@ -1820,6 +1824,7 @@ void tst_qdeclarativetextinput::echoMode() QCOMPARE(input->text(), initial); QCOMPARE(input->displayText(), QLatin1String("********")); QCOMPARE(input->inputMethodHints(), ref); + QCOMPARE(input->imHints(), Qt::ImhNone); input->setPasswordCharacter(QChar('Q')); QCOMPARE(input->passwordCharacter(), QLatin1String("Q")); QCOMPARE(input->text(), initial); @@ -1829,6 +1834,7 @@ void tst_qdeclarativetextinput::echoMode() ref &= ~Qt::ImhHiddenText; ref |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText); QCOMPARE(input->inputMethodHints(), ref); + QCOMPARE(input->imHints(), Qt::ImhNone); QCOMPARE(input->text(), initial); QCOMPARE(input->displayText(), QLatin1String("QQQQQQQQ")); QCOMPARE(input->inputMethodQuery(Qt::ImSurroundingText).toString(), QLatin1String("QQQQQQQQ")); @@ -1849,6 +1855,40 @@ void tst_qdeclarativetextinput::echoMode() QCOMPARE(input->displayText(), initial); QCOMPARE(input->inputMethodQuery(Qt::ImSurroundingText).toString(), initial); + // Test echo mode doesn't override imHints. + input->setIMHints(Qt::ImhHiddenText | Qt::ImhDialableCharactersOnly); + ref |= Qt::ImhDialableCharactersOnly; + //Normal + input->setEchoMode(QDeclarativeTextInput::Normal); + ref |= Qt::ImhHiddenText; + ref &= ~(Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText); + QCOMPARE(input->inputMethodHints(), ref); + QCOMPARE(input->imHints(), Qt::ImhHiddenText | Qt::ImhDialableCharactersOnly); + //NoEcho + input->setEchoMode(QDeclarativeTextInput::NoEcho); + ref |= Qt::ImhHiddenText; + ref |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText); + QCOMPARE(input->inputMethodHints(), ref); + QCOMPARE(input->imHints(), Qt::ImhHiddenText | Qt::ImhDialableCharactersOnly); + //Password + input->setEchoMode(QDeclarativeTextInput::Password); + ref |= Qt::ImhHiddenText; + ref |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText); + QCOMPARE(input->inputMethodHints(), ref); + QCOMPARE(input->imHints(), Qt::ImhHiddenText | Qt::ImhDialableCharactersOnly); + //PasswordEchoOnEdit + input->setEchoMode(QDeclarativeTextInput::PasswordEchoOnEdit); + ref &= ~Qt::ImhHiddenText; + ref |= (Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText); + QCOMPARE(input->inputMethodHints(), ref); + QCOMPARE(input->imHints(), Qt::ImhHiddenText | Qt::ImhDialableCharactersOnly); + //Normal + input->setEchoMode(QDeclarativeTextInput::Normal); + ref |= Qt::ImhHiddenText; + ref &= ~(Qt::ImhNoAutoUppercase | Qt::ImhNoPredictiveText); + QCOMPARE(input->inputMethodHints(), ref); + QCOMPARE(input->imHints(), Qt::ImhHiddenText | Qt::ImhDialableCharactersOnly); + delete canvas; } -- cgit v0.12 From 60198a071dd76e57ab799215f0fbddc8d550ba30 Mon Sep 17 00:00:00 2001 From: Andrew den Exter Date: Tue, 19 Apr 2011 15:11:36 +1000 Subject: Fix TextInput cursor position unchanged when selection length is 0. Move the cursor position to the start position when both the new and old selections are empty as would happen if either was non-empty. Change-Id: I493e52c551b47e009fd13b3e95856ff012ee5d95 Task-number: QTBUG-18768 Reviewed-by: Martin Jones --- src/gui/widgets/qlinecontrol.cpp | 10 +++++++++- .../qdeclarativetextedit/tst_qdeclarativetextedit.cpp | 10 ++++++++++ .../qdeclarativetextinput/tst_qdeclarativetextinput.cpp | 9 +++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp index d03e5de..202ea7a 100644 --- a/src/gui/widgets/qlinecontrol.cpp +++ b/src/gui/widgets/qlinecontrol.cpp @@ -254,12 +254,20 @@ void QLineControl::setSelection(int start, int length) m_selstart = start; m_selend = qMin(start + length, (int)m_text.length()); m_cursor = m_selend; - } else { + } else if (length < 0){ if (start == m_selend && start + length == m_selstart) return; m_selstart = qMax(start + length, 0); m_selend = start; m_cursor = m_selstart; + } else if (m_selstart != m_selend) { + m_selstart = 0; + m_selend = 0; + m_cursor = start; + } else { + m_cursor = start; + emitCursorPositionChanged(); + return; } emit selectionChanged(); emitCursorPositionChanged(); diff --git a/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp b/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp index 574d2d5..26a6fd8 100644 --- a/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp +++ b/tests/auto/declarative/qdeclarativetextedit/tst_qdeclarativetextedit.cpp @@ -788,6 +788,14 @@ void tst_qdeclarativetextedit::selection() QCOMPARE(textEditObject->selectionEnd(), i); QVERIFY(textEditObject->selectedText().isNull()); } + //Test cursor follows selection + for(int i=0; i<= testStr.size(); i++) { + textEditObject->select(i,i); + QCOMPARE(textEditObject->cursorPosition(), i); + QCOMPARE(textEditObject->selectionStart(), i); + QCOMPARE(textEditObject->selectionEnd(), i); + } + textEditObject->setCursorPosition(0); QVERIFY(textEditObject->cursorPosition() == 0); @@ -812,10 +820,12 @@ void tst_qdeclarativetextedit::selection() for(int i=0; i<= testStr.size(); i++) { textEditObject->select(0,i); QCOMPARE(testStr.mid(0,i), textEditObject->selectedText()); + QCOMPARE(textEditObject->cursorPosition(), i); } for(int i=0; i<= testStr.size(); i++) { textEditObject->select(i,testStr.size()); QCOMPARE(testStr.mid(i,testStr.size()-i), textEditObject->selectedText()); + QCOMPARE(textEditObject->cursorPosition(), testStr.size()); } textEditObject->setCursorPosition(0); diff --git a/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp b/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp index 79d95d3..baaf862 100644 --- a/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp +++ b/tests/auto/declarative/qdeclarativetextinput/tst_qdeclarativetextinput.cpp @@ -375,6 +375,13 @@ void tst_qdeclarativetextinput::selection() QCOMPARE(textinputObject->selectionEnd(), i); QVERIFY(textinputObject->selectedText().isNull()); } + //Test cursor follows selection + for(int i=0; i<= testStr.size(); i++) { + textinputObject->select(i,i); + QCOMPARE(textinputObject->cursorPosition(), i); + QCOMPARE(textinputObject->selectionStart(), i); + QCOMPARE(textinputObject->selectionEnd(), i); + } textinputObject->setCursorPosition(0); QVERIFY(textinputObject->cursorPosition() == 0); @@ -399,10 +406,12 @@ void tst_qdeclarativetextinput::selection() for(int i=0; i<= testStr.size(); i++) { textinputObject->select(0,i); QCOMPARE(testStr.mid(0,i), textinputObject->selectedText()); + QCOMPARE(textinputObject->cursorPosition(), i); } for(int i=0; i<= testStr.size(); i++) { textinputObject->select(i,testStr.size()); QCOMPARE(testStr.mid(i,testStr.size()-i), textinputObject->selectedText()); + QCOMPARE(textinputObject->cursorPosition(), testStr.size()); } textinputObject->setCursorPosition(0); -- cgit v0.12 From f14ac31c86eeb53d0b08c799ad0ad895d17475d6 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Thu, 21 Apr 2011 16:17:46 +1000 Subject: Document section behavior when not ordered by section Change-Id: Id0345d477c253a5dd54306b06dae1df971ec76fc Task-number: QTBUG-17757 Reviewed-by: Bea Lam --- src/declarative/graphicsitems/qdeclarativelistview.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/declarative/graphicsitems/qdeclarativelistview.cpp b/src/declarative/graphicsitems/qdeclarativelistview.cpp index 7c01293..2e9822e 100644 --- a/src/declarative/graphicsitems/qdeclarativelistview.cpp +++ b/src/declarative/graphicsitems/qdeclarativelistview.cpp @@ -2302,11 +2302,19 @@ void QDeclarativeListView::setCacheBuffer(int b) depending on the "size" property of the model item. The \c sectionHeading delegate component provides the light blue bar that marks the beginning of each section. + \snippet examples/declarative/modelviews/listview/sections.qml 0 \image qml-listview-sections-example.png + \note Adding sections to a ListView does not automatically re-order the + list items by the section criteria. + If the model is not ordered by section, then it is possible that + the sections created will not be unique; each boundary between + differing sections will result in a section header being created + even if that section exists elsewhere. + \sa {declarative/modelviews/listview}{ListView examples} */ QDeclarativeViewSection *QDeclarativeListView::sectionCriteria() -- cgit v0.12 From 8e1fd720f61c6704050d731a1e6b0a31cd7706bd Mon Sep 17 00:00:00 2001 From: Steffen Hansen Date: Wed, 20 Apr 2011 12:45:42 +0200 Subject: Use binary search to speed up findChildFrame() Merge-request: 2595 Reviewed-by: mae --- src/gui/text/qtextdocument_p.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/gui/text/qtextdocument_p.cpp b/src/gui/text/qtextdocument_p.cpp index 2172f74..a997720 100644 --- a/src/gui/text/qtextdocument_p.cpp +++ b/src/gui/text/qtextdocument_p.cpp @@ -1406,11 +1406,18 @@ void QTextDocumentPrivate::changeObjectFormat(QTextObject *obj, int format) static QTextFrame *findChildFrame(QTextFrame *f, int pos) { - // ##### use binary search - QList children = f->childFrames(); - for (int i = 0; i < children.size(); ++i) { - QTextFrame *c = children.at(i); - if (pos >= c->firstPosition() && pos <= c->lastPosition()) + /* Binary search for frame at pos */ + const QList children = f->childFrames(); + int first = 0; + int last = children.size() - 1; + while (first <= last) { + int mid = (first + last) / 2; + QTextFrame *c = children.at(mid); + if (pos > c->lastPosition()) + first = mid + 1; + else if (pos < c->firstPosition()) + last = mid - 1; + else return c; } return 0; -- cgit v0.12