diff options
author | Kent Hansen <kent.hansen@nokia.com> | 2012-03-23 14:31:47 +0100 |
---|---|---|
committer | Kent Hansen <kent.hansen@nokia.com> | 2012-03-23 14:31:47 +0100 |
commit | 0655209fdad022bd0f6eb20ce85522cb56506bf0 (patch) | |
tree | cdba0c1590655f5cb75a68cedff74f8a683db3a2 /src/qml | |
parent | c3babc03c99c6ca5fa210486e133eb456a405bab (diff) | |
parent | 3d8f103c2641f35e7681485102a1b59886db8934 (diff) |
Merge master into api_changes
Conflicts:
src/qml/qml/qqmlboundsignal.cpp
src/qml/qml/qqmlpropertycache.cpp
Change-Id: I5193a193fa301c0b518291645bf626a5fa07118f
Diffstat (limited to 'src/qml')
43 files changed, 336 insertions, 859 deletions
diff --git a/src/qml/debugger/debugger.pri b/src/qml/debugger/debugger.pri index f5abd2c196..f16e225cfd 100644 --- a/src/qml/debugger/debugger.pri +++ b/src/qml/debugger/debugger.pri @@ -1,5 +1,4 @@ SOURCES += \ - $$PWD/qpacketprotocol.cpp \ $$PWD/qqmldebugservice.cpp \ $$PWD/qqmlprofilerservice.cpp \ $$PWD/qqmldebugserver.cpp \ @@ -10,7 +9,6 @@ SOURCES += \ $$PWD/qdebugmessageservice.cpp HEADERS += \ - $$PWD/qpacketprotocol_p.h \ $$PWD/qqmldebugservice_p.h \ $$PWD/qqmldebugservice_p_p.h \ $$PWD/qqmlprofilerservice_p.h \ diff --git a/src/qml/debugger/qpacketprotocol.cpp b/src/qml/debugger/qpacketprotocol.cpp deleted file mode 100644 index 978054a238..0000000000 --- a/src/qml/debugger/qpacketprotocol.cpp +++ /dev/null @@ -1,550 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qpacketprotocol_p.h" - -#include <QtCore/QBuffer> -#include <QtCore/QElapsedTimer> - -QT_BEGIN_NAMESPACE - -static const unsigned int MAX_PACKET_SIZE = 0x7FFFFFFF; - -/*! - \class QPacketProtocol - \internal - - \brief The QPacketProtocol class encapsulates communicating discrete packets - across fragmented IO channels, such as TCP sockets. - - QPacketProtocol makes it simple to send arbitrary sized data "packets" across - fragmented transports such as TCP and UDP. - - As transmission boundaries are not respected, sending packets over protocols - like TCP frequently involves "stitching" them back together at the receiver. - QPacketProtocol makes this easier by performing this task for you. Packet - data sent using QPacketProtocol is prepended with a 4-byte size header - allowing the receiving QPacketProtocol to buffer the packet internally until - it has all been received. QPacketProtocol does not perform any sanity - checking on the size or on the data, so this class should only be used in - prototyping or trusted situations where DOS attacks are unlikely. - - QPacketProtocol does not perform any communications itself. Instead it can - operate on any QIODevice that supports the QIODevice::readyRead() signal. A - logical "packet" is encapsulated by the companion QPacket class. The - following example shows two ways to send data using QPacketProtocol. The - transmitted data is equivalent in both. - - \code - QTcpSocket socket; - // ... connect socket ... - - QPacketProtocol protocol(&socket); - - // Send packet the quick way - protocol.send() << "Hello world" << 123; - - // Send packet the longer way - QPacket packet; - packet << "Hello world" << 123; - protocol.send(packet); - \endcode - - Likewise, the following shows how to read data from QPacketProtocol, assuming - that the QPacketProtocol::readyRead() signal has been emitted. - - \code - // ... QPacketProtocol::readyRead() is emitted ... - - int a; - QByteArray b; - - // Receive packet the quick way - protocol.read() >> a >> b; - - // Receive packet the longer way - QPacket packet = protocol.read(); - p >> a >> b; - \endcode - - \ingroup io - \sa QPacket -*/ - -class QPacketProtocolPrivate : public QObject -{ - Q_OBJECT -public: - QPacketProtocolPrivate(QPacketProtocol *parent, QIODevice *_dev) - : QObject(parent), inProgressSize(-1), maxPacketSize(MAX_PACKET_SIZE), - waitingForPacket(false), dev(_dev) - { - Q_ASSERT(4 == sizeof(qint32)); - - QObject::connect(this, SIGNAL(readyRead()), - parent, SIGNAL(readyRead())); - QObject::connect(this, SIGNAL(packetWritten()), - parent, SIGNAL(packetWritten())); - QObject::connect(this, SIGNAL(invalidPacket()), - parent, SIGNAL(invalidPacket())); - QObject::connect(dev, SIGNAL(readyRead()), - this, SLOT(readyToRead())); - QObject::connect(dev, SIGNAL(aboutToClose()), - this, SLOT(aboutToClose())); - QObject::connect(dev, SIGNAL(bytesWritten(qint64)), - this, SLOT(bytesWritten(qint64))); - } - -Q_SIGNALS: - void readyRead(); - void packetWritten(); - void invalidPacket(); - -public Q_SLOTS: - void aboutToClose() - { - inProgress.clear(); - sendingPackets.clear(); - inProgressSize = -1; - } - - void bytesWritten(qint64 bytes) - { - Q_ASSERT(!sendingPackets.isEmpty()); - - while (bytes) { - if (sendingPackets.at(0) > bytes) { - sendingPackets[0] -= bytes; - bytes = 0; - } else { - bytes -= sendingPackets.at(0); - sendingPackets.removeFirst(); - emit packetWritten(); - } - } - } - - void readyToRead() - { - while (true) { - // Need to get trailing data - if (-1 == inProgressSize) { - // We need a size header of sizeof(qint32) - if (sizeof(qint32) > (uint)dev->bytesAvailable()) - return; - - // Read size header - int read = dev->read((char *)&inProgressSize, sizeof(qint32)); - Q_ASSERT(read == sizeof(qint32)); - Q_UNUSED(read); - - // Check sizing constraints - if (inProgressSize > maxPacketSize) { - QObject::disconnect(dev, SIGNAL(readyRead()), - this, SLOT(readyToRead())); - QObject::disconnect(dev, SIGNAL(aboutToClose()), - this, SLOT(aboutToClose())); - QObject::disconnect(dev, SIGNAL(bytesWritten(qint64)), - this, SLOT(bytesWritten(qint64))); - dev = 0; - emit invalidPacket(); - return; - } - - inProgressSize -= sizeof(qint32); - } else { - inProgress.append(dev->read(inProgressSize - inProgress.size())); - - if (inProgressSize == inProgress.size()) { - // Packet has arrived! - packets.append(inProgress); - inProgressSize = -1; - inProgress.clear(); - - waitingForPacket = false; - emit readyRead(); - } else - return; - } - } - } - -public: - QList<qint64> sendingPackets; - QList<QByteArray> packets; - QByteArray inProgress; - qint32 inProgressSize; - qint32 maxPacketSize; - bool waitingForPacket; - QIODevice *dev; -}; - -/*! - Construct a QPacketProtocol instance that works on \a dev with the - specified \a parent. - */ -QPacketProtocol::QPacketProtocol(QIODevice *dev, QObject *parent) - : QObject(parent), d(new QPacketProtocolPrivate(this, dev)) -{ - Q_ASSERT(dev); -} - -/*! - Destroys the QPacketProtocol instance. - */ -QPacketProtocol::~QPacketProtocol() -{ -} - -/*! - Returns the maximum packet size allowed. By default this is - 2,147,483,647 bytes. - - If a packet claiming to be larger than the maximum packet size is received, - the QPacketProtocol::invalidPacket() signal is emitted. - - \sa QPacketProtocol::setMaximumPacketSize() - */ -qint32 QPacketProtocol::maximumPacketSize() const -{ - return d->maxPacketSize; -} - -/*! - Sets the maximum allowable packet size to \a max. - - \sa QPacketProtocol::maximumPacketSize() - */ -qint32 QPacketProtocol::setMaximumPacketSize(qint32 max) -{ - if (max > (signed)sizeof(qint32)) - d->maxPacketSize = max; - return d->maxPacketSize; -} - -/*! - Returns a streamable object that is transmitted on destruction. For example - - \code - protocol.send() << "Hello world" << 123; - \endcode - - will send a packet containing "Hello world" and 123. To construct more - complex packets, explicitly construct a QPacket instance. - */ -QPacketAutoSend QPacketProtocol::send() -{ - return QPacketAutoSend(this); -} - -/*! - \fn void QPacketProtocol::send(const QPacket & packet) - - Transmit the \a packet. - */ -void QPacketProtocol::send(const QPacket & p) -{ - if (p.b.isEmpty()) - return; // We don't send empty packets - - qint64 sendSize = p.b.size() + sizeof(qint32); - - d->sendingPackets.append(sendSize); - qint32 sendSize32 = sendSize; - qint64 writeBytes = d->dev->write((char *)&sendSize32, sizeof(qint32)); - Q_ASSERT(writeBytes == sizeof(qint32)); - writeBytes = d->dev->write(p.b); - Q_ASSERT(writeBytes == p.b.size()); -} - -/*! - Returns the number of received packets yet to be read. - */ -qint64 QPacketProtocol::packetsAvailable() const -{ - return d->packets.count(); -} - -/*! - Discard any unread packets. - */ -void QPacketProtocol::clear() -{ - d->packets.clear(); -} - -/*! - Return the next unread packet, or an invalid QPacket instance if no packets - are available. This method does NOT block. - */ -QPacket QPacketProtocol::read() -{ - if (0 == d->packets.count()) - return QPacket(); - - QPacket rv(d->packets.at(0)); - d->packets.removeFirst(); - return rv; -} - -/* - Returns the difference between msecs and elapsed. If msecs is -1, - however, -1 is returned. -*/ -static int qt_timeout_value(int msecs, int elapsed) -{ - if (msecs == -1) - return -1; - - int timeout = msecs - elapsed; - return timeout < 0 ? 0 : timeout; -} - -/*! - This function locks until a new packet is available for reading and the - \l{QIODevice::}{readyRead()} signal has been emitted. The function - will timeout after \a msecs milliseconds; the default timeout is - 30000 milliseconds. - - The function returns true if the readyRead() signal is emitted and - there is new data available for reading; otherwise it returns false - (if an error occurred or the operation timed out). - */ - -bool QPacketProtocol::waitForReadyRead(int msecs) -{ - if (!d->packets.isEmpty()) - return true; - - QElapsedTimer stopWatch; - stopWatch.start(); - - d->waitingForPacket = true; - do { - if (!d->dev->waitForReadyRead(msecs)) - return false; - if (!d->waitingForPacket) - return true; - msecs = qt_timeout_value(msecs, stopWatch.elapsed()); - } while (true); -} - -/*! - Return the QIODevice passed to the QPacketProtocol constructor. -*/ -QIODevice *QPacketProtocol::device() -{ - return d->dev; -} - -/*! - \fn void QPacketProtocol::readyRead() - - Emitted whenever a new packet is received. Applications may use - QPacketProtocol::read() to retrieve this packet. - */ - -/*! - \fn void QPacketProtocol::invalidPacket() - - A packet larger than the maximum allowable packet size was received. The - packet will be discarded and, as it indicates corruption in the protocol, no - further packets will be received. - */ - -/*! - \fn void QPacketProtocol::packetWritten() - - Emitted each time a packet is completing written to the device. This signal - may be used for communications flow control. - */ - -/*! - \class QPacket - \internal - - \brief The QPacket class encapsulates an unfragmentable packet of data to be - transmitted by QPacketProtocol. - - The QPacket class works together with QPacketProtocol to make it simple to - send arbitrary sized data "packets" across fragmented transports such as TCP - and UDP. - - QPacket provides a QDataStream interface to an unfragmentable packet. - Applications should construct a QPacket, propagate it with data and then - transmit it over a QPacketProtocol instance. For example: - \code - QPacketProtocol protocol(...); - - QPacket myPacket; - myPacket << "Hello world!" << 123; - protocol.send(myPacket); - \endcode - - As long as both ends of the connection are using the QPacketProtocol class, - the data within this packet will be delivered unfragmented at the other end, - ready for extraction. - - \code - QByteArray greeting; - int count; - - QPacket myPacket = protocol.read(); - - myPacket >> greeting >> count; - \endcode - - Only packets returned from QPacketProtocol::read() may be read from. QPacket - instances constructed by directly by applications are for transmission only - and are considered "write only". Attempting to read data from them will - result in undefined behavior. - - \ingroup io - \sa QPacketProtocol - */ - -/*! - Constructs an empty write-only packet. - */ -QPacket::QPacket() - : QDataStream(), buf(0) -{ - buf = new QBuffer(&b); - buf->open(QIODevice::WriteOnly); - setDevice(buf); - setVersion(QDataStream::Qt_4_7); -} - -/*! - Destroys the QPacket instance. - */ -QPacket::~QPacket() -{ - if (buf) { - delete buf; - buf = 0; - } -} - -/*! - Creates a copy of \a other. The initial stream positions are shared, but the - two packets are otherwise independent. - */ -QPacket::QPacket(const QPacket & other) - : QDataStream(), b(other.b), buf(0) -{ - buf = new QBuffer(&b); - buf->open(other.buf->openMode()); - setDevice(buf); -} - -/*! - \internal - */ -QPacket::QPacket(const QByteArray & ba) - : QDataStream(), b(ba), buf(0) -{ - buf = new QBuffer(&b); - buf->open(QIODevice::ReadOnly); - setDevice(buf); -} - -/*! - Returns true if this packet is empty - that is, contains no data. - */ -bool QPacket::isEmpty() const -{ - return b.isEmpty(); -} - -/*! - Returns raw packet data. - */ -QByteArray QPacket::data() const -{ - return b; -} - -/*! - Clears data in the packet. This is useful for reusing one writable packet. - For example - \code - QPacketProtocol protocol(...); - - QPacket packet; - - packet << "Hello world!" << 123; - protocol.send(packet); - - packet.clear(); - packet << "Goodbyte world!" << 789; - protocol.send(packet); - \endcode - */ -void QPacket::clear() -{ - QBuffer::OpenMode oldMode = buf->openMode(); - buf->close(); - b.clear(); - buf->setBuffer(&b); // reset QBuffer internals with new size of b. - buf->open(oldMode); -} - -/*! - \class QPacketAutoSend - \internal - - \internal - */ -QPacketAutoSend::QPacketAutoSend(QPacketProtocol *_p) - : QPacket(), p(_p) -{ -} - -QPacketAutoSend::~QPacketAutoSend() -{ - if (!b.isEmpty()) - p->send(*this); -} - -QT_END_NAMESPACE - -#include <qpacketprotocol.moc> diff --git a/src/qml/debugger/qpacketprotocol_p.h b/src/qml/debugger/qpacketprotocol_p.h deleted file mode 100644 index c6123d2836..0000000000 --- a/src/qml/debugger/qpacketprotocol_p.h +++ /dev/null @@ -1,137 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QPACKETPROTOCOL_H -#define QPACKETPROTOCOL_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 <QtCore/qobject.h> -#include <QtCore/qdatastream.h> - -#include <private/qtqmlglobal_p.h> - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - - -class QIODevice; -class QBuffer; -class QPacket; -class QPacketAutoSend; -class QPacketProtocolPrivate; - -class Q_QML_PRIVATE_EXPORT QPacketProtocol : public QObject -{ - Q_OBJECT -public: - explicit QPacketProtocol(QIODevice *dev, QObject *parent = 0); - virtual ~QPacketProtocol(); - - qint32 maximumPacketSize() const; - qint32 setMaximumPacketSize(qint32); - - QPacketAutoSend send(); - void send(const QPacket &); - - qint64 packetsAvailable() const; - QPacket read(); - - bool waitForReadyRead(int msecs = 3000); - - void clear(); - - QIODevice *device(); - -Q_SIGNALS: - void readyRead(); - void invalidPacket(); - void packetWritten(); - -private: - QPacketProtocolPrivate *d; -}; - - -class Q_QML_PRIVATE_EXPORT QPacket : public QDataStream -{ -public: - QPacket(); - QPacket(const QPacket &); - virtual ~QPacket(); - - void clear(); - bool isEmpty() const; - QByteArray data() const; - -protected: - friend class QPacketProtocol; - QPacket(const QByteArray &ba); - QByteArray b; - QBuffer *buf; -}; - -class Q_QML_PRIVATE_EXPORT QPacketAutoSend : public QPacket -{ -public: - virtual ~QPacketAutoSend(); - -private: - friend class QPacketProtocol; - QPacketAutoSend(QPacketProtocol *); - QPacketProtocol *p; -}; - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif diff --git a/src/qml/debugger/qqmldebugserver.cpp b/src/qml/debugger/qqmldebugserver.cpp index ec3f9dafc2..dcf93b400e 100644 --- a/src/qml/debugger/qqmldebugserver.cpp +++ b/src/qml/debugger/qqmldebugserver.cpp @@ -117,9 +117,10 @@ public: m_pluginName = pluginName; } - void setPort(int port, bool block) { + void setPort(int port, bool block, QString &hostAddress) { m_port = port; m_block = block; + m_hostAddress = hostAddress; } void run(); @@ -128,6 +129,7 @@ private: QString m_pluginName; int m_port; bool m_block; + QString m_hostAddress; }; QQmlDebugServerPrivate::QQmlDebugServerPrivate() : @@ -214,7 +216,7 @@ void QQmlDebugServerThread::run() = server->d_func()->loadConnectionPlugin(m_pluginName); if (connection) { connection->setServer(QQmlDebugServer::instance()); - connection->setPort(m_port, m_block); + connection->setPort(m_port, m_block, m_hostAddress); } else { QCoreApplicationPrivate *appD = static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(qApp)); qWarning() << QString(QLatin1String("QML Debugger: Ignoring \"-qmljsdebugger=%1\". " @@ -258,8 +260,9 @@ QQmlDebugServer *QQmlDebugServer::instance() int port = 0; bool block = false; bool ok = false; + QString hostAddress; - // format: qmljsdebugger=port:3768[,block] OR qmljsdebugger=ost[,block] + // format: qmljsdebugger=port:3768[,host:<ip address>][,block] OR qmljsdebugger=ost[,block] if (!appD->qmljsDebugArgumentsString().isEmpty()) { if (!QQmlEnginePrivate::qml_debugging_enabled) { qWarning() << QString(QLatin1String( @@ -270,24 +273,30 @@ QQmlDebugServer *QQmlDebugServer::instance() } 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 = QStringLiteral("qmldbg_tcp"); - } else if (appD->qmljsDebugArgumentsString().contains(QLatin1String("ost"))) { - pluginName = QStringLiteral("qmldbg_ost"); - ok = true; + QStringList lstjsDebugArguments = appD->qmljsDebugArgumentsString() + .split(QLatin1Char(',')); + foreach (const QString &strArgument, lstjsDebugArguments) { + if (strArgument.startsWith(QLatin1String("port:"))) { + port = strArgument.mid(5).toInt(&ok); + pluginName = QLatin1String("qmldbg_tcp"); + } else if (strArgument.startsWith(QLatin1String("host:"))) { + hostAddress = strArgument.mid(5); + } else if (strArgument == QLatin1String("block")) { + block = true; + } else { + qWarning() << QString::fromLatin1("QML Debugger: Invalid argument '%1' " + "detected. Ignoring the same.") + .arg(strArgument); + } } - block = appD->qmljsDebugArgumentsString().contains(QLatin1String("block")); - if (ok) { qQmlDebugServer = new QQmlDebugServer(); QQmlDebugServerThread *thread = new QQmlDebugServerThread; qQmlDebugServer->d_func()->thread = thread; qQmlDebugServer->moveToThread(thread); thread->setPluginName(pluginName); - thread->setPort(port, block); + thread->setPort(port, block, hostAddress); thread->start(); if (block) { diff --git a/src/qml/debugger/qqmldebugserverconnection_p.h b/src/qml/debugger/qqmldebugserverconnection_p.h index ab9e7bd73f..920e82ed47 100644 --- a/src/qml/debugger/qqmldebugserverconnection_p.h +++ b/src/qml/debugger/qqmldebugserverconnection_p.h @@ -69,7 +69,7 @@ public: virtual ~QQmlDebugServerConnection() {} virtual void setServer(QQmlDebugServer *server) = 0; - virtual void setPort(int port, bool bock) = 0; + virtual void setPort(int port, bool bock, const QString &hostaddress) = 0; virtual bool isConnected() const = 0; virtual void send(const QList<QByteArray> &messages) = 0; virtual void disconnect() = 0; diff --git a/src/qml/debugger/qqmlenginedebugservice.cpp b/src/qml/debugger/qqmlenginedebugservice.cpp index 67bec3577b..7f0bf7ca33 100644 --- a/src/qml/debugger/qqmlenginedebugservice.cpp +++ b/src/qml/debugger/qqmlenginedebugservice.cpp @@ -67,7 +67,7 @@ QQmlEngineDebugService *QQmlEngineDebugService::instance() } QQmlEngineDebugService::QQmlEngineDebugService(QObject *parent) - : QQmlDebugService(QStringLiteral("QDeclarativeEngine"), 1, parent), + : QQmlDebugService(QStringLiteral("QmlDebugger"), 1, parent), m_watch(new QQmlWatcher(this)), m_statesDelegate(0) { @@ -394,12 +394,10 @@ void QQmlEngineDebugService::processMessage(const QByteArray &message) QDataStream ds(message); QByteArray type; - ds >> type; + int queryId; + ds >> type >> queryId; if (type == "LIST_ENGINES") { - int queryId; - ds >> queryId; - QByteArray reply; QDataStream rs(&reply, QIODevice::WriteOnly); rs << QByteArray("LIST_ENGINES_R"); @@ -416,9 +414,8 @@ void QQmlEngineDebugService::processMessage(const QByteArray &message) sendMessage(reply); } else if (type == "LIST_OBJECTS") { - int queryId; int engineId = -1; - ds >> queryId >> engineId; + ds >> engineId; QQmlEngine *engine = qobject_cast<QQmlEngine *>(QQmlDebugService::objectForId(engineId)); @@ -443,12 +440,11 @@ void QQmlEngineDebugService::processMessage(const QByteArray &message) sendMessage(reply); } else if (type == "FETCH_OBJECT") { - int queryId; int objectId; bool recurse; bool dumpProperties = true; - ds >> queryId >> objectId >> recurse >> dumpProperties; + ds >> objectId >> recurse >> dumpProperties; QObject *object = QQmlDebugService::objectForId(objectId); @@ -464,10 +460,9 @@ void QQmlEngineDebugService::processMessage(const QByteArray &message) sendMessage(reply); } else if (type == "WATCH_OBJECT") { - int queryId; int objectId; - ds >> queryId >> objectId; + ds >> objectId; bool ok = m_watch->addWatch(queryId, objectId); QByteArray reply; @@ -476,11 +471,10 @@ void QQmlEngineDebugService::processMessage(const QByteArray &message) sendMessage(reply); } else if (type == "WATCH_PROPERTY") { - int queryId; int objectId; QByteArray property; - ds >> queryId >> objectId >> property; + ds >> objectId >> property; bool ok = m_watch->addWatch(queryId, objectId, property); QByteArray reply; @@ -489,11 +483,10 @@ void QQmlEngineDebugService::processMessage(const QByteArray &message) sendMessage(reply); } else if (type == "WATCH_EXPR_OBJECT") { - int queryId; int debugId; QString expr; - ds >> queryId >> debugId >> expr; + ds >> debugId >> expr; bool ok = m_watch->addWatch(queryId, debugId, expr); QByteArray reply; @@ -501,16 +494,17 @@ void QQmlEngineDebugService::processMessage(const QByteArray &message) rs << QByteArray("WATCH_EXPR_OBJECT_R") << queryId << ok; sendMessage(reply); } else if (type == "NO_WATCH") { - int queryId; + bool ok = m_watch->removeWatch(queryId); - ds >> queryId; - m_watch->removeWatch(queryId); + QByteArray reply; + QDataStream rs(&reply, QIODevice::WriteOnly); + rs << QByteArray("NO_WATCH_R") << queryId << ok; + sendMessage(reply); } else if (type == "EVAL_EXPRESSION") { - int queryId; int objectId; QString expr; - ds >> queryId >> objectId >> expr; + ds >> objectId >> expr; QObject *object = QQmlDebugService::objectForId(objectId); QQmlContext *context = qmlContext(object); @@ -539,26 +533,43 @@ void QQmlEngineDebugService::processMessage(const QByteArray &message) bool isLiteralValue; QString filename; int line; - ds >> objectId >> propertyName >> expr >> isLiteralValue; - if (!ds.atEnd()) { // backward compatibility from 2.1, 2.2 - ds >> filename >> line; - } - setBinding(objectId, propertyName, expr, isLiteralValue, filename, line); + ds >> objectId >> propertyName >> expr >> isLiteralValue >> + filename >> line; + bool ok = setBinding(objectId, propertyName, expr, isLiteralValue, + filename, line); + + QByteArray reply; + QDataStream rs(&reply, QIODevice::WriteOnly); + rs << QByteArray("SET_BINDING_R") << queryId << ok; + + sendMessage(reply); } else if (type == "RESET_BINDING") { int objectId; QString propertyName; ds >> objectId >> propertyName; - resetBinding(objectId, propertyName); + bool ok = resetBinding(objectId, propertyName); + + QByteArray reply; + QDataStream rs(&reply, QIODevice::WriteOnly); + rs << QByteArray("RESET_BINDING_R") << queryId << ok; + + sendMessage(reply); } else if (type == "SET_METHOD_BODY") { int objectId; QString methodName; QString methodBody; ds >> objectId >> methodName >> methodBody; - setMethodBody(objectId, methodName, methodBody); + bool ok = setMethodBody(objectId, methodName, methodBody); + + QByteArray reply; + QDataStream rs(&reply, QIODevice::WriteOnly); + rs << QByteArray("SET_METHOD_BODY_R") << queryId << ok; + + sendMessage(reply); } } -void QQmlEngineDebugService::setBinding(int objectId, +bool QQmlEngineDebugService::setBinding(int objectId, const QString &propertyName, const QVariant &expression, bool isLiteralValue, @@ -566,6 +577,7 @@ void QQmlEngineDebugService::setBinding(int objectId, int line, int column) { + bool ok = true; QObject *object = objectForId(objectId); QQmlContext *context = qmlContext(object); @@ -594,22 +606,23 @@ void QQmlEngineDebugService::setBinding(int objectId, oldBinding->destroy(); binding->update(); } else { + ok = false; qWarning() << "QQmlEngineDebugService::setBinding: unable to set property" << propertyName << "on object" << object; } } } else { // not a valid property - bool ok = false; if (m_statesDelegate) ok = m_statesDelegate->setBindingForInvalidProperty(object, propertyName, expression, isLiteralValue); if (!ok) qWarning() << "QQmlEngineDebugService::setBinding: unable to set property" << propertyName << "on object" << object; } } + return ok; } -void QQmlEngineDebugService::resetBinding(int objectId, const QString &propertyName) +bool QQmlEngineDebugService::resetBinding(int objectId, const QString &propertyName) { QObject *object = objectForId(objectId); QQmlContext *context = qmlContext(object); @@ -651,24 +664,25 @@ void QQmlEngineDebugService::resetBinding(int objectId, const QString &propertyN m_statesDelegate->resetBindingForInvalidProperty(object, propertyName); } } + return true; } -void QQmlEngineDebugService::setMethodBody(int objectId, const QString &method, const QString &body) +bool QQmlEngineDebugService::setMethodBody(int objectId, const QString &method, const QString &body) { QObject *object = objectForId(objectId); QQmlContext *context = qmlContext(object); if (!object || !context || !context->engine()) - return; + return false; QQmlContextData *contextData = QQmlContextData::get(context); if (!contextData) - return; + return false; QQmlPropertyData dummy; QQmlPropertyData *prop = QQmlPropertyCache::property(context->engine(), object, method, dummy); if (!prop || !prop->isVMEFunction()) - return; + return false; QMetaMethod metaMethod = object->metaObject()->method(prop->coreIndex); QList<QByteArray> paramNames = metaMethod.parameterNames(); @@ -690,6 +704,7 @@ void QQmlEngineDebugService::setMethodBody(int objectId, const QString &method, int lineNumber = vmeMetaObject->vmeMethodLineNumber(prop->coreIndex); vmeMetaObject->setVmeMethod(prop->coreIndex, QQmlExpressionPrivate::evalFunction(contextData, object, jsfunction, contextData->url.toString(), lineNumber)); + return true; } void QQmlEngineDebugService::propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value) @@ -729,7 +744,8 @@ void QQmlEngineDebugService::objectCreated(QQmlEngine *engine, QObject *object) QByteArray reply; QDataStream rs(&reply, QIODevice::WriteOnly); - rs << QByteArray("OBJECT_CREATED") << engineId << objectId; + //unique queryId -1 + rs << QByteArray("OBJECT_CREATED") << -1 << engineId << objectId; sendMessage(reply); } diff --git a/src/qml/debugger/qqmlenginedebugservice_p.h b/src/qml/debugger/qqmlenginedebugservice_p.h index f41063d7a3..19a5776e27 100644 --- a/src/qml/debugger/qqmlenginedebugservice_p.h +++ b/src/qml/debugger/qqmlenginedebugservice_p.h @@ -119,9 +119,9 @@ private: QQmlObjectData objectData(QObject *); QQmlObjectProperty propertyData(QObject *, int); QVariant valueContents(const QVariant &defaultValue) const; - void setBinding(int objectId, const QString &propertyName, const QVariant &expression, bool isLiteralValue, QString filename = QString(), int line = -1, int column = 0); - void resetBinding(int objectId, const QString &propertyName); - void setMethodBody(int objectId, const QString &method, const QString &body); + bool setBinding(int objectId, const QString &propertyName, const QVariant &expression, bool isLiteralValue, QString filename = QString(), int line = -1, int column = 0); + bool resetBinding(int objectId, const QString &propertyName); + bool setMethodBody(int objectId, const QString &method, const QString &body); QList<QQmlEngine *> m_engines; QQmlWatcher *m_watch; diff --git a/src/qml/debugger/qqmlprofilerservice_p.h b/src/qml/debugger/qqmlprofilerservice_p.h index 7a708456ba..2b4cafb615 100644 --- a/src/qml/debugger/qqmlprofilerservice_p.h +++ b/src/qml/debugger/qqmlprofilerservice_p.h @@ -54,12 +54,15 @@ // #include <private/qqmldebugservice_p.h> -#include <QtQml/qtqmlglobal.h> +#include "qqmlexpression.h" + #include <QtCore/qelapsedtimer.h> +#include <QtCore/qmetaobject.h> #include <QtCore/qmutex.h> #include <QtCore/qvector.h> #include <QtCore/qstringbuilder.h> + QT_BEGIN_HEADER QT_BEGIN_NAMESPACE @@ -194,47 +197,30 @@ struct QQmlBindingProfiler { QQmlProfilerService::instance->endRange(QQmlProfilerService::Binding); } - void addDetail(const QString &details) - { - if (enabled) - QQmlProfilerService::instance->rangeData(QQmlProfilerService::Binding, - details); - } -\ bool enabled; }; struct QQmlHandlingSignalProfiler { - QQmlHandlingSignalProfiler() + QQmlHandlingSignalProfiler(const QMetaMethod &signal, QQmlExpression *expression) { enabled = QQmlProfilerService::instance ? QQmlProfilerService::instance->profilingEnabled() : false; if (enabled) { - QQmlProfilerService::instance->startRange( - QQmlProfilerService::HandlingSignal); + QQmlProfilerService *service = QQmlProfilerService::instance; + service->startRange(QQmlProfilerService::HandlingSignal); + service->rangeData(QQmlProfilerService::HandlingSignal, + QString::fromLatin1(signal.methodSignature()) + QLatin1String(": ") + + expression->expression()); + service->rangeLocation(QQmlProfilerService::HandlingSignal, + expression->sourceFile(), expression->lineNumber(), + expression->columnNumber()); } } - void setSignalInfo(const QString &name, const QString &expression) - { - if (enabled) - QQmlProfilerService::instance->rangeData( - QQmlProfilerService::HandlingSignal, - name % QLatin1String(": ") % expression); - } - - void setLocation(const QString &file, int line, int column) - { - if (enabled) - QQmlProfilerService::instance->rangeLocation( - QQmlProfilerService::HandlingSignal, file, line, column); - } - ~QQmlHandlingSignalProfiler() { if (enabled) - QQmlProfilerService::instance->endRange( - QQmlProfilerService::HandlingSignal); + QQmlProfilerService::instance->endRange(QQmlProfilerService::HandlingSignal); } bool enabled; @@ -243,22 +229,23 @@ struct QQmlHandlingSignalProfiler { struct QQmlObjectCreatingProfiler { QQmlObjectCreatingProfiler() { - QQmlProfilerService *instance = QQmlProfilerService::instance; - enabled = instance ? - instance->profilingEnabled() : false; - if (enabled) - instance->startRange(QQmlProfilerService::Creating); + enabled = QQmlProfilerService::instance + ? QQmlProfilerService::instance->profilingEnabled() : false; + if (enabled) { + QQmlProfilerService *service = QQmlProfilerService::instance; + service->startRange(QQmlProfilerService::Creating); + } } void setTypeName(const QString &typeName) { - if (enabled) - QQmlProfilerService::instance->rangeData( - QQmlProfilerService::Creating, typeName); + Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled."); + QQmlProfilerService::instance->rangeData(QQmlProfilerService::Creating, typeName); } void setLocation(const QUrl &url, int line, int column) { + Q_ASSERT_X(enabled, Q_FUNC_INFO, "method called although profiler is not enabled."); if (enabled) QQmlProfilerService::instance->rangeLocation( QQmlProfilerService::Creating, url, line, column); diff --git a/src/qml/debugger/qv8debugservice.cpp b/src/qml/debugger/qv8debugservice.cpp index a6aeda31d5..7d54a59ac0 100644 --- a/src/qml/debugger/qv8debugservice.cpp +++ b/src/qml/debugger/qv8debugservice.cpp @@ -42,6 +42,7 @@ #include "qv8debugservice_p.h" #include "qqmldebugservice_p_p.h" #include <private/qjsconverter_impl_p.h> +#include <private/qv4compiler_p.h> #include <private/qv8engine_p.h> #include <QtCore/QHash> @@ -192,6 +193,7 @@ void QV8DebugService::init() Q_D(QV8DebugService); v8::Debug::SetMessageHandler2(DebugMessageHandler); v8::Debug::SetDebugMessageDispatchHandler(DebugMessageDispatchHandler); + QV4Compiler::enableV4(false); d->initializeMutex.unlock(); } diff --git a/src/qml/debugger/qv8profilerservice.cpp b/src/qml/debugger/qv8profilerservice.cpp index 6208676522..c75c258785 100644 --- a/src/qml/debugger/qv8profilerservice.cpp +++ b/src/qml/debugger/qv8profilerservice.cpp @@ -52,20 +52,19 @@ Q_GLOBAL_STATIC(QV8ProfilerService, v8ProfilerInstance) class DebugServiceOutputStream : public v8::OutputStream { - QQmlDebugService &_service; public: - DebugServiceOutputStream(QQmlDebugService &service) - : v8::OutputStream(), - _service(service) {} + DebugServiceOutputStream() + : v8::OutputStream() {} void EndOfStream() {} WriteResult WriteAsciiChunk(char *rawData, int size) { QByteArray data; QDataStream ds(&data, QIODevice::WriteOnly); ds << QV8ProfilerService::V8SnapshotChunk << QByteArray(rawData, size); - _service.sendMessage(data); + messages.append(data); return kContinue; } + QList<QByteArray> messages; }; // convert to a QByteArray that can be sent to the debug client @@ -267,16 +266,18 @@ void QV8ProfilerServicePrivate::takeSnapshot(v8::HeapSnapshot::Type snapshotType v8::HandleScope scope; v8::Local<v8::String> title = v8::String::New(""); - DebugServiceOutputStream outputStream(*q); + DebugServiceOutputStream outputStream; const v8::HeapSnapshot *snapshot = v8::HeapProfiler::TakeSnapshot(title, snapshotType); snapshot->Serialize(&outputStream, v8::HeapSnapshot::kJSON); + QList<QByteArray> messages = outputStream.messages; //indicate completion QByteArray data; QDataStream ds(&data, QIODevice::WriteOnly); ds << (int)QV8ProfilerService::V8SnapshotComplete; + messages.append(data); - q->sendMessage(data); + q->sendMessages(messages); } void QV8ProfilerServicePrivate::sendMessages() @@ -285,16 +286,16 @@ void QV8ProfilerServicePrivate::sendMessages() QList<QByteArray> messages; for (int i = 0; i < m_data.count(); ++i) - messages << m_data.at(i).toByteArray(); - q->sendMessages(messages); + messages.append(m_data.at(i).toByteArray()); m_data.clear(); //indicate completion QByteArray data; QDataStream ds(&data, QIODevice::WriteOnly); ds << (int)QV8ProfilerService::V8Complete; + messages.append(data); - q->sendMessage(data); + q->sendMessages(messages); } diff --git a/src/qml/qml/ftw/qhashedstring_p.h b/src/qml/qml/ftw/qhashedstring_p.h index f575285ff6..f058f21e98 100644 --- a/src/qml/qml/ftw/qhashedstring_p.h +++ b/src/qml/qml/ftw/qhashedstring_p.h @@ -59,6 +59,10 @@ #include <private/qflagpointer_p.h> +#if defined(Q_OS_QNX) +#include <stdlib.h> +#endif + QT_BEGIN_NAMESPACE // Enable this to debug hash linking assumptions. diff --git a/src/qml/qml/ftw/qqmlpool.cpp b/src/qml/qml/ftw/qqmlpool.cpp index 6fd11d4b1e..64df87ada5 100644 --- a/src/qml/qml/ftw/qqmlpool.cpp +++ b/src/qml/qml/ftw/qqmlpool.cpp @@ -41,6 +41,10 @@ #include "qqmlpool_p.h" +#ifdef Q_OS_QNX +#include <malloc.h> +#endif + // #define POOL_DEBUG QT_BEGIN_NAMESPACE diff --git a/src/qml/qml/qqmlaccessors_p.h b/src/qml/qml/qqmlaccessors_p.h index a603bede9f..8e67a58511 100644 --- a/src/qml/qml/qqmlaccessors_p.h +++ b/src/qml/qml/qqmlaccessors_p.h @@ -47,6 +47,10 @@ #include <QtCore/qhash.h> #include <QtCore/QReadWriteLock> +#ifdef Q_OS_QNX +#include <stdint.h> +#endif + QT_BEGIN_HEADER QT_BEGIN_NAMESPACE diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp index f43822ed0e..c4f48ef63d 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -193,8 +193,6 @@ void QQmlBinding::update(QQmlPropertyPrivate::WriteFlags flags) if (!updatingFlag()) { QQmlBindingProfiler prof(m_url, m_lineNumber, m_columnNumber); - if (prof.enabled) - prof.addDetail(expression()); setUpdatingFlag(true); QQmlAbstractExpression::DeleteWatcher watcher(this); diff --git a/src/qml/qml/qqmlboundsignal.cpp b/src/qml/qml/qqmlboundsignal.cpp index aa130d9493..f7d0c00a5c 100644 --- a/src/qml/qml/qqmlboundsignal.cpp +++ b/src/qml/qml/qqmlboundsignal.cpp @@ -174,13 +174,7 @@ int QQmlBoundSignal::qt_metacall(QMetaObject::Call c, int id, void **a) if (QQmlDebugService::isDebuggingEnabled()) QV8DebugService::instance()->signalEmitted(QString::fromAscii(m_signal.methodSignature().constData())); - QQmlHandlingSignalProfiler prof; - if (prof.enabled) { - prof.setSignalInfo(QString::fromLatin1(m_signal.methodSignature().constData()), - m_expression->expression()); - prof.setLocation(m_expression->sourceFile(), m_expression->lineNumber(), - m_expression->columnNumber()); - } + QQmlHandlingSignalProfiler prof(m_signal, m_expression); m_isEvaluating = true; if (!m_paramsValid) { @@ -233,7 +227,10 @@ QQmlBoundSignalParameters::QQmlBoundSignalParameters(const QMetaMethod &method, prop.setWritable(false); } else { QByteArray propType = type; - if (t >= int(QVariant::UserType) || t == QMetaType::UnknownType || t == QMetaType::Void) { + if ((QMetaType::typeFlags(t) & QMetaType::IsEnumeration) == QMetaType::IsEnumeration) { + t = QVariant::Int; + propType = "int"; + } else if (t == QMetaType::UnknownType) { QByteArray scope; QByteArray name; int scopeIdx = propType.lastIndexOf("::"); diff --git a/src/qml/qml/qqmlcompiler.cpp b/src/qml/qml/qqmlcompiler.cpp index c3b8152ce1..dec9911481 100644 --- a/src/qml/qml/qqmlcompiler.cpp +++ b/src/qml/qml/qqmlcompiler.cpp @@ -2217,7 +2217,7 @@ bool QQmlCompiler::buildValueTypeProperty(QObject *type, //optimization for <Type>.<EnumValue> enum assignments bool isEnumAssignment = false; - if (prop->core.isEnum()) + if (prop->core.isEnum() || prop->core.propType == QMetaType::Int) COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, value, &isEnumAssignment)); if (isEnumAssignment) { @@ -2485,7 +2485,7 @@ bool QQmlCompiler::buildPropertyLiteralAssignment(QQmlScript::Property *prop, if (v->value.isScript()) { //optimization for <Type>.<EnumValue> enum assignments - if (prop->core.isEnum()) { + if (prop->core.isEnum() || prop->core.propType == QMetaType::Int) { bool isEnumAssignment = false; COMPILE_CHECK(testQualifiedEnumAssignment(prop, obj, v, &isEnumAssignment)); if (isEnumAssignment) { @@ -2515,8 +2515,9 @@ bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop, QQmlScript::Value *v, bool *isAssignment) { + bool isIntProp = (prop->core.propType == QMetaType::Int) && !prop->core.isEnum(); *isAssignment = false; - if (!prop->core.isEnum()) + if (!prop->core.isEnum() && !isIntProp) return true; QMetaProperty mprop = obj->metaObject()->property(prop->index); @@ -2528,6 +2529,17 @@ bool QQmlCompiler::testQualifiedEnumAssignment(QQmlScript::Property *prop, if (!string.at(0).isUpper()) return true; + if (isIntProp) { + // Allow enum assignment to ints. + int enumval = evaluateEnum(string.toUtf8()); + if (enumval != -1) { + v->type = Value::Literal; + v->value = QQmlScript::Variant((double)enumval); + *isAssignment = true; + } + return true; + } + QStringList parts = string.split(QLatin1Char('.')); if (parts.count() != 2) return true; diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 6cd5cf6cec..416178e3e1 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -829,7 +829,10 @@ QQmlComponentPrivate::beginCreate(QQmlContextData *context) if (rv) { QQmlData *ddata = QQmlData::get(rv); Q_ASSERT(ddata); + //top level objects should never get JS ownership. + //if JS ownership is needed this needs to be explicitly undone (like in component.createObject()) ddata->indestructible = true; + ddata->explicitIndestructibleSet = true; } if (enginePriv->isDebugging && rv) { @@ -1120,7 +1123,8 @@ void QQmlComponent::createObject(QQmlV8Function *args) d->completeCreate(); Q_ASSERT(QQmlData::get(rv)); - QQmlData::get(rv)->setImplicitDestructible(); + QQmlData::get(rv)->explicitIndestructibleSet = false; + QQmlData::get(rv)->indestructible = false; if (!rv) args->returnValue(v8::Null()); @@ -1255,10 +1259,6 @@ void QQmlComponentPrivate::initializeObjectWithInitialProperties(v8::Handle<v8:: v8::Handle<v8::Value> args[] = { object, valuemap }; v8::Handle<v8::Function>::Cast(function)->Call(v8engine->global(), 2, args); } - - QQmlData *ddata = QQmlData::get(toCreate); - Q_ASSERT(ddata); - ddata->setImplicitDestructible(); } diff --git a/src/qml/qml/qqmlcontext_p.h b/src/qml/qml/qqmlcontext_p.h index d10543bde5..97bc04b91d 100644 --- a/src/qml/qml/qqmlcontext_p.h +++ b/src/qml/qml/qqmlcontext_p.h @@ -146,7 +146,7 @@ public: quint32 isJSContext:1; quint32 isPragmaLibraryContext:1; quint32 unresolvedNames:1; // True if expressions in this context failed to resolve a toplevel name - quint32 dummy:28; + quint32 dummy:27; QQmlContext *publicContext; // VME data that is constructing this context if any diff --git a/src/qml/qml/qqmldirparser.cpp b/src/qml/qml/qqmldirparser.cpp index 7b99214f04..df5f7f8ee9 100644 --- a/src/qml/qml/qqmldirparser.cpp +++ b/src/qml/qml/qqmldirparser.cpp @@ -295,4 +295,18 @@ QList<QQmlDirParser::TypeInfo> QQmlDirParser::typeInfos() const } #endif +QDebug &operator<< (QDebug &debug, const QQmlDirParser::Component &component) +{ + return debug << qPrintable(QString("{%1 %2.%3}").arg(component.typeName) + .arg(component.majorVersion) + .arg(component.minorVersion)); +} + +QDebug &operator<< (QDebug &debug, const QQmlDirParser::Script &script) +{ + return debug << qPrintable(QString("{%1 %2.%3}").arg(script.nameSpace) + .arg(script.majorVersion) + .arg(script.minorVersion)); +} + QT_END_NAMESPACE diff --git a/src/qml/qml/qqmldirparser_p.h b/src/qml/qml/qqmldirparser_p.h index 8c681309ac..f46e1781da 100644 --- a/src/qml/qml/qqmldirparser_p.h +++ b/src/qml/qml/qqmldirparser_p.h @@ -55,6 +55,7 @@ #include <QtCore/QUrl> #include <QtCore/QHash> +#include <QtCore/QDebug> QT_BEGIN_NAMESPACE @@ -160,6 +161,8 @@ private: typedef QList<QQmlDirParser::Component> QQmlDirComponents; typedef QList<QQmlDirParser::Script> QQmlDirScripts; +QDebug &operator<< (QDebug &, const QQmlDirParser::Component &); +QDebug &operator<< (QDebug &, const QQmlDirParser::Script &); QT_END_NAMESPACE diff --git a/src/qml/qml/qqmlextensionplugin.cpp b/src/qml/qml/qqmlextensionplugin.cpp index b69fa5da7a..86d9f9588d 100644 --- a/src/qml/qml/qqmlextensionplugin.cpp +++ b/src/qml/qml/qqmlextensionplugin.cpp @@ -97,7 +97,7 @@ QT_BEGIN_NAMESPACE \code TEMPLATE = lib CONFIG += qt plugin - QT += declarative + QT += qml DESTDIR = com/nokia/TimeExample TARGET = qmlqtimeexampleplugin diff --git a/src/qml/qml/qqmlimport.cpp b/src/qml/qml/qqmlimport.cpp index 0c1fb3bd93..1224efdaac 100644 --- a/src/qml/qml/qqmlimport.cpp +++ b/src/qml/qml/qqmlimport.cpp @@ -117,7 +117,7 @@ public: QList<QQmlError> *errors); QString resolvedUri(const QString &dir_arg, QQmlImportDatabase *database); - bool add(const QQmlDirComponents &qmldircomponentsnetwork, + QString add(const QQmlDirComponents &qmldircomponentsnetwork, const QString& uri_arg, const QString& prefix, int vmaj, int vmin, QQmlScript::Import::Type importType, QQmlImportDatabase *database, QList<QQmlError> *errors); @@ -493,7 +493,7 @@ QString QQmlImportsPrivate::resolvedUri(const QString &dir_arg, QQmlImportDataba return stableRelativePath; } -bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork, +QString QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork, const QString& uri_arg, const QString& prefix, int vmaj, int vmin, QQmlScript::Import::Type importType, QQmlImportDatabase *database, QList<QQmlError> *errors) @@ -540,7 +540,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork, url = QUrl::fromLocalFile(fi.absolutePath()).toString(); uri = resolvedUri(dir, database); if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, &qmldirscripts, errors)) - return false; + return QString(); break; } } @@ -564,7 +564,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork, url = QUrl::fromLocalFile(fi.absolutePath()).toString(); uri = resolvedUri(dir, database); if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, &qmldirscripts, errors)) - return false; + return QString(); break; } } @@ -586,7 +586,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork, url = QUrl::fromLocalFile(absolutePath).toString(); uri = resolvedUri(dir, database); if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, &qmldirscripts, errors)) - return false; + return QString(); break; } } @@ -604,7 +604,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork, error.setDescription(QQmlImportDatabase::tr("module \"%1\" is not installed").arg(uri_arg)); errors->prepend(error); } - return false; + return QString(); } } else { if (importType == QQmlScript::Import::File && qmldircomponents.isEmpty()) { @@ -619,14 +619,14 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork, error.setUrl(QUrl(importUrl)); errors->prepend(error); } - return false; // local import dirs must exist + return QString(); // local import dirs must exist } uri = resolvedUri(dir, database); if (uri.endsWith(Slash)) uri.chop(1); if (!typeLoader->absoluteFilePath(localFileOrQrc).isEmpty()) { if (!importExtension(localFileOrQrc,uri,database,&qmldircomponents,&qmldirscripts,errors)) - return false; + return QString(); } } else { if (prefix.isEmpty()) { @@ -642,7 +642,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork, error.setUrl(QUrl(importUrl)); errors->prepend(error); } - return false; + return QString(); } } } @@ -669,7 +669,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork, error.setDescription(QQmlImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri_arg).arg(vmaj).arg(vmin)); errors->prepend(error); } - return false; + return QString(); } } @@ -686,7 +686,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork, QQmlError error; error.setDescription(QQmlImportDatabase::tr("\"%1\" is ambiguous. Found in %2 and in %3").arg(uri).arg(url).arg(it->url)); errors->prepend(error); - return false; + return QString(); } } @@ -716,7 +716,7 @@ bool QQmlImportsPrivate::add(const QQmlDirComponents &qmldircomponentsnetwork, s->imports.prepend(data); - return true; + return data.url; } bool QQmlImportsPrivate::find(const QString& type, int *vmajor, int *vminor, QQmlType** type_return, @@ -874,9 +874,11 @@ QQmlImportDatabase::~QQmlImportDatabase() The \a prefix may be empty, in which case the import location is considered for unqualified types. + Returns the resolved URL of the import on success. + The base URL must already have been set with Import::setBaseUrl(). */ -bool QQmlImports::addImport(QQmlImportDatabase *importDb, +QString QQmlImports::addImport(QQmlImportDatabase *importDb, const QString& uri, const QString& prefix, int vmaj, int vmin, QQmlScript::Import::Type importType, const QQmlDirComponents &qmldircomponentsnetwork, diff --git a/src/qml/qml/qqmlimport_p.h b/src/qml/qml/qqmlimport_p.h index ff19510525..422f2429a0 100644 --- a/src/qml/qml/qqmlimport_p.h +++ b/src/qml/qml/qqmlimport_p.h @@ -93,7 +93,7 @@ public: QQmlType** type_return, QString* url_return, int *version_major, int *version_minor) const; - bool addImport(QQmlImportDatabase *, + QString addImport(QQmlImportDatabase *, const QString& uri, const QString& prefix, int vmaj, int vmin, QQmlScript::Import::Type importType, const QQmlDirComponents &qmldircomponentsnetwork, diff --git a/src/qml/qml/qqmlincubator.cpp b/src/qml/qml/qqmlincubator.cpp index aa9777d89e..fad2ae2f28 100644 --- a/src/qml/qml/qqmlincubator.cpp +++ b/src/qml/qml/qqmlincubator.cpp @@ -293,8 +293,9 @@ void QQmlIncubatorPrivate::incubate(QQmlVME::Interrupt &i) if (result) { QQmlData *ddata = QQmlData::get(result); Q_ASSERT(ddata); + //see QQmlComponent::beginCreate for explanation of indestructible ddata->indestructible = true; - + ddata->explicitIndestructibleSet = true; q->setInitialState(result); } diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 5b80f57d01..4af08c28bf 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -512,7 +512,7 @@ QObject *QQmlType::create() const d->m_newFunc(rv); if (rv && !d->m_metaObjects.isEmpty()) - (void *)new QQmlProxyMetaObject(rv, &d->m_metaObjects); + (void)new QQmlProxyMetaObject(rv, &d->m_metaObjects); return rv; } @@ -525,7 +525,7 @@ void QQmlType::create(QObject **out, void **memory, size_t additionalMemory) con d->m_newFunc(rv); if (rv && !d->m_metaObjects.isEmpty()) - (void *)new QQmlProxyMetaObject(rv, &d->m_metaObjects); + (void)new QQmlProxyMetaObject(rv, &d->m_metaObjects); *out = rv; *memory = ((char *)rv) + d->m_allocationSize; diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index afab665ea4..4a1eb79213 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -674,7 +674,13 @@ QStringList QQmlPropertyCache::propertyNames() const return keys; } -static int EnumType(const QMetaObject *meta, const QByteArray &str) +struct StaticQtMetaObject : public QObject +{ + static const QMetaObject *get() + { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; } +}; + +static int EnumType(const QMetaObject *metaobj, const QByteArray &str) { QByteArray scope; QByteArray name; @@ -685,6 +691,11 @@ static int EnumType(const QMetaObject *meta, const QByteArray &str) } else { name = str; } + const QMetaObject *meta; + if (scope == "Qt") + meta = StaticQtMetaObject::get(); + else + meta = metaobj; for (int i = meta->enumeratorCount() - 1; i >= 0; --i) { QMetaEnum m = meta->enumerator(i); if ((m.name() == name) && (scope.isEmpty() || (m.scope() == scope))) @@ -727,12 +738,14 @@ int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index, for (int ii = 0; ii < argc; ++ii) { int type = m.parameterType(ii); - if (type == QVariant::Invalid) { + if ((QMetaType::typeFlags(type) & QMetaType::IsEnumeration) == QMetaType::IsEnumeration) + type = QVariant::Int; + else if (type == QMetaType::UnknownType) { if (argTypeNames.isEmpty()) argTypeNames = m.parameterTypes(); type = EnumType(object->metaObject(), argTypeNames.at(ii)); } - if (type == QVariant::Invalid) { + if (type == QMetaType::UnknownType) { if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii); free(args); return 0; @@ -754,12 +767,14 @@ int *QQmlPropertyCache::methodParameterTypes(QObject *object, int index, for (int ii = 0; ii < argc; ++ii) { int type = m.parameterType(ii); - if (type == QVariant::Invalid) { + if ((QMetaType::typeFlags(type) & QMetaType::IsEnumeration) == QMetaType::IsEnumeration) + type = QVariant::Int; + else if (type == QMetaType::UnknownType) { if (argTypeNames.isEmpty()) argTypeNames = m.parameterTypes(); type = EnumType(object->metaObject(), argTypeNames.at(ii)); } - if (type == QVariant::Invalid) { + if (type == QMetaType::UnknownType) { if (unknownTypeError) *unknownTypeError = argTypeNames.at(ii); return 0; } diff --git a/src/qml/qml/qqmlstringconverters.cpp b/src/qml/qml/qqmlstringconverters.cpp index 473097fab0..04b63ea7cd 100644 --- a/src/qml/qml/qqmlstringconverters.cpp +++ b/src/qml/qml/qqmlstringconverters.cpp @@ -128,6 +128,9 @@ QDateTime QQmlStringConverters::dateTimeFromString(const QString &s, bool *ok) { QDateTime d = QDateTime::fromString(s, Qt::ISODate); if (ok) *ok = d.isValid(); + // V8 never parses a date string as local time. For consistency do the same here. + if (d.timeSpec() == Qt::LocalTime) + d.setTimeSpec(Qt::UTC); return d; } #endif // QT_NO_DATESTRING diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 781915e23e..abe2c0bfa4 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -1558,7 +1558,6 @@ void QQmlTypeData::dataReceived(const QByteArray &data) ref.qualifier = import.qualifier; ref.script = blob; m_scripts << ref; - } } @@ -1657,8 +1656,8 @@ void QQmlTypeData::resolveTypes() import.extractVersion(&vmaj, &vmin); QList<QQmlError> errors; - if (!m_imports.addImport(importDatabase, import.uri, import.qualifier, - vmaj, vmin, import.type, qmldircomponentsnetwork, &errors)) { + if (m_imports.addImport(importDatabase, import.uri, import.qualifier, vmaj, vmin, + import.type, qmldircomponentsnetwork, &errors).isNull()) { QQmlError error; if (errors.size()) { error = errors.takeFirst(); @@ -1859,8 +1858,9 @@ void QQmlScriptBlob::dataReceived(const QByteArray &data) import.extractVersion(&vmaj, &vmin); QList<QQmlError> errors; - if (!m_imports.addImport(importDatabase, import.uri, import.qualifier, vmaj, vmin, - import.type, QQmlDirComponents(), &errors)) { + QString importUrl = m_imports.addImport(importDatabase, import.uri, import.qualifier, vmaj, vmin, + import.type, QQmlDirComponents(), &errors); + if (importUrl.isNull()) { QQmlError error = errors.takeFirst(); // description should be set by addImport(). error.setUrl(m_imports.baseUrl()); @@ -1871,6 +1871,22 @@ void QQmlScriptBlob::dataReceived(const QByteArray &data) setError(errors); return; } + + // Does this library contain any scripts? + QUrl libraryUrl(importUrl); + const QQmlDirParser *dirParser = typeLoader()->qmlDirParser(libraryUrl.path() + QLatin1String("qmldir")); + foreach (const QQmlDirParser::Script &script, dirParser->scripts()) { + QUrl scriptUrl = libraryUrl.resolved(QUrl(script.fileName)); + QQmlScriptBlob *blob = typeLoader()->getScript(scriptUrl); + addDependency(blob); + + ScriptReference ref; + ref.location = import.location.start; + ref.qualifier = script.nameSpace; + ref.nameSpace = import.qualifier; + ref.script = blob; + m_scripts << ref; + } } } } @@ -1902,11 +1918,20 @@ void QQmlScriptBlob::done() m_scriptData->urlString = finalUrlString(); m_scriptData->importCache = new QQmlTypeNameCache(); - for (int ii = 0; !isError() && ii < m_scripts.count(); ++ii) { - const ScriptReference &script = m_scripts.at(ii); + QSet<QString> ns; + + for (int scriptIndex = 0; !isError() && scriptIndex < m_scripts.count(); ++scriptIndex) { + const ScriptReference &script = m_scripts.at(scriptIndex); m_scriptData->scripts.append(script.script); - m_scriptData->importCache->add(script.qualifier, ii); + + if (!script.nameSpace.isNull()) { + if (!ns.contains(script.nameSpace)) { + ns.insert(script.nameSpace); + m_scriptData->importCache->add(script.nameSpace); + } + } + m_scriptData->importCache->add(script.qualifier, scriptIndex, script.nameSpace); } m_imports.populateCache(m_scriptData->importCache, engine); diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index c8c2756bd5..319b2e7a10 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -390,6 +390,7 @@ public: QQmlScript::Location location; QString qualifier; + QString nameSpace; QQmlScriptBlob *script; }; diff --git a/src/qml/qml/qqmlvme.cpp b/src/qml/qml/qqmlvme.cpp index 6309335e59..352684ed5e 100644 --- a/src/qml/qml/qqmlvme.cpp +++ b/src/qml/qml/qqmlvme.cpp @@ -829,7 +829,7 @@ QObject *QQmlVME::run(QList<QQmlError> *errors, bindValues.push(binding); binding->m_mePtr = &bindValues.top(); - Q_ASSERT(binding->propertyIndex() == property); + Q_ASSERT(binding->propertyIndex() == (property & 0xFF00FFFF)); Q_ASSERT(binding->object() == target); binding->addToObject(); diff --git a/src/qml/qml/qqmlwatcher.cpp b/src/qml/qml/qqmlwatcher.cpp index 500185762f..4eaa3d2c2a 100644 --- a/src/qml/qml/qqmlwatcher.cpp +++ b/src/qml/qml/qqmlwatcher.cpp @@ -166,13 +166,14 @@ bool QQmlWatcher::addWatch(int id, quint32 objectId, const QString &expr) return false; } -void QQmlWatcher::removeWatch(int id) +bool QQmlWatcher::removeWatch(int id) { if (!m_proxies.contains(id)) - return; + return false; QList<QPointer<QQmlWatchProxy> > proxies = m_proxies.take(id); qDeleteAll(proxies); + return true; } void QQmlWatcher::addPropertyWatch(int id, QObject *object, quint32 debugId, const QMetaProperty &property) diff --git a/src/qml/qml/qqmlwatcher_p.h b/src/qml/qml/qqmlwatcher_p.h index 70dc9d468c..3ca2c83777 100644 --- a/src/qml/qml/qqmlwatcher_p.h +++ b/src/qml/qml/qqmlwatcher_p.h @@ -77,7 +77,7 @@ public: bool addWatch(int id, quint32 objectId, const QByteArray &property); bool addWatch(int id, quint32 objectId, const QString &expr); - void removeWatch(int id); + bool removeWatch(int id); Q_SIGNALS: void propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value); diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index df1712976c..56743eb915 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -1384,7 +1384,7 @@ void QQmlXMLHttpRequest::readEncoding() if (header.first == "content-type") { int separatorIdx = header.second.indexOf(';'); if (separatorIdx == -1) { - m_mime == header.second; + m_mime = header.second; } else { m_mime = header.second.mid(0, separatorIdx); int charsetIdx = header.second.indexOf("charset="); diff --git a/src/qml/qml/v4/qv4bindings.cpp b/src/qml/qml/v4/qv4bindings.cpp index 38a3acafa2..0cd6ffd082 100644 --- a/src/qml/qml/v4/qv4bindings.cpp +++ b/src/qml/qml/v4/qv4bindings.cpp @@ -1153,6 +1153,25 @@ void QV4Bindings::run(int instrIndex, quint32 &executedBlocks, } QML_V4_END_INSTR(ConvertColorToString, unaryop) + QML_V4_BEGIN_INSTR(ConvertObjectToBool, unaryop) + { + const Register &src = registers[instr->unaryop.src]; + Register &output = registers[instr->unaryop.output]; + // ### NaN + if (src.isUndefined()) + output.setUndefined(); + else + output.setbool(src.getQObject() != 0); + } + QML_V4_END_INSTR(ConvertObjectToBool, unaryop) + + QML_V4_BEGIN_INSTR(ConvertNullToObject, unaryop) + { + Register &output = registers[instr->unaryop.output]; + output.setQObject(0); + } + QML_V4_END_INSTR(ConvertNullToObject, unaryop) + QML_V4_BEGIN_INSTR(ResolveUrl, unaryop) { const Register &src = registers[instr->unaryop.src]; diff --git a/src/qml/qml/v4/qv4compiler.cpp b/src/qml/qml/v4/qv4compiler.cpp index 09b0f3861b..c9495e8987 100644 --- a/src/qml/qml/v4/qv4compiler.cpp +++ b/src/qml/qml/v4/qv4compiler.cpp @@ -54,7 +54,6 @@ QT_BEGIN_NAMESPACE DEFINE_BOOL_CONFIG_OPTION(bindingsDump, QML_BINDINGS_DUMP) DEFINE_BOOL_CONFIG_OPTION(qmlDisableOptimizer, QML_DISABLE_OPTIMIZER) -DEFINE_BOOL_CONFIG_OPTION(qmlExperimental, QML_EXPERIMENTAL) DEFINE_BOOL_CONFIG_OPTION(qmlVerboseCompiler, QML_VERBOSE_COMPILER) DEFINE_BOOL_CONFIG_OPTION(qmlBindingsTestEnv, QML_BINDINGS_TEST) @@ -958,6 +957,7 @@ void QV4CompilerPrivate::visitMove(IR::Move *s) case IR::StringType: opcode = V4Instr::ConvertStringToBool; break; case IR::UrlType: opcode = V4Instr::ConvertUrlToBool; break; case IR::ColorType: opcode = V4Instr::ConvertColorToBool; break; + case IR::ObjectType: opcode = V4Instr::ConvertObjectToBool; break; default: break; } // switch } else if (targetTy == IR::IntType) { @@ -1010,6 +1010,11 @@ void QV4CompilerPrivate::visitMove(IR::Move *s) case IR::StringType: opcode = V4Instr::ConvertStringToColor; break; default: break; } // switch + } else if (targetTy == IR::ObjectType) { + switch (sourceTy) { + case IR::NullType: opcode = V4Instr::ConvertNullToObject; break; + default: break; + } // switch } if (opcode != V4Instr::Noop) { V4Instr conv; @@ -1354,9 +1359,6 @@ int QV4Compiler::compile(const Expression &expression, QQmlEnginePrivate *engine { if (!expression.expression.asAST()) return false; - if (!qmlExperimental() && expression.property->isValueTypeSubProperty) - return -1; - if (qmlDisableOptimizer() || !qmlEnableV4) return -1; diff --git a/src/qml/qml/v4/qv4instruction.cpp b/src/qml/qml/v4/qv4instruction.cpp index 1ed8bd245e..cb6ff40589 100644 --- a/src/qml/qml/v4/qv4instruction.cpp +++ b/src/qml/qml/v4/qv4instruction.cpp @@ -189,6 +189,12 @@ void Bytecode::dump(const V4Instr *i, int address) const case V4Instr::ConvertColorToString: INSTR_DUMP << "\t" << "ConvertColorToString" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; + case V4Instr::ConvertObjectToBool: + INSTR_DUMP << "\t" << "ConvertObjectToBool" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; + break; + case V4Instr::ConvertNullToObject: + INSTR_DUMP << "\t" << "ConvertNullToObject" << "\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; + break; case V4Instr::ResolveUrl: INSTR_DUMP << "\t" << "ResolveUrl" << "\t\t" << "Input_Reg(" << i->unaryop.src << ") -> Output_Reg(" << i->unaryop.output << ")"; break; diff --git a/src/qml/qml/v4/qv4instruction_p.h b/src/qml/qml/v4/qv4instruction_p.h index d6c790e46f..239cb362cc 100644 --- a/src/qml/qml/v4/qv4instruction_p.h +++ b/src/qml/qml/v4/qv4instruction_p.h @@ -98,6 +98,8 @@ QT_BEGIN_NAMESPACE F(ConvertUrlToString, unaryop) \ F(ConvertColorToBool, unaryop) \ F(ConvertColorToString, unaryop) \ + F(ConvertObjectToBool, unaryop) \ + F(ConvertNullToObject, unaryop) \ F(ResolveUrl, unaryop) \ F(MathSinReal, unaryop) \ F(MathCosReal, unaryop) \ diff --git a/src/qml/qml/v4/qv4irbuilder.cpp b/src/qml/qml/v4/qv4irbuilder.cpp index 481b23eb4a..ea4d1afbbc 100644 --- a/src/qml/qml/v4/qv4irbuilder.cpp +++ b/src/qml/qml/v4/qv4irbuilder.cpp @@ -428,7 +428,7 @@ bool QV4IRBuilder::visit(AST::IdentifierExpression *ast) if (r.isValid()) { if (r.type) { _expr.code = _block->ATTACH_TYPE(name, r.type, IR::Name::ScopeStorage, line, column); - } else if (r.importNamespace) { + } /*else if (r.importNamespace) { QQmlMetaType::ModuleApiInstance *moduleApi = m_expression->importCache->moduleApi(r.importNamespace); if (moduleApi) { if (moduleApi->qobjectCallback) { @@ -439,7 +439,7 @@ bool QV4IRBuilder::visit(AST::IdentifierExpression *ast) if (moduleApi->qobjectApi) _expr.code = _block->MODULE_OBJECT(name, moduleApi->qobjectApi->metaObject(), IR::Name::MemberStorage, line, column); } - } + }*/ //### we can't create the actual QObject here, as we may be running in a thread (can be reenabled once QTBUG-24894 is handled) // We don't support anything else } else { bool found = false; diff --git a/src/qml/qml/v8/qjsconverter_impl_p.h b/src/qml/qml/v8/qjsconverter_impl_p.h index 10b8ab5fae..c2775df7f5 100644 --- a/src/qml/qml/v8/qjsconverter_impl_p.h +++ b/src/qml/qml/v8/qjsconverter_impl_p.h @@ -44,6 +44,10 @@ #ifndef QJSCONVERTER_IMPL_P_H #define QJSCONVERTER_IMPL_P_H +#ifdef Q_OS_QNX +#include <malloc.h> +#endif + QT_BEGIN_NAMESPACE extern char *qdtoa(double d, int mode, int ndigits, int *decpt, int *sign, char **rve, char **digits_str); diff --git a/src/qml/qml/v8/qjsvalue.cpp b/src/qml/qml/v8/qjsvalue.cpp index 4471e68a61..6ecb97d2e5 100644 --- a/src/qml/qml/v8/qjsvalue.cpp +++ b/src/qml/qml/v8/qjsvalue.cpp @@ -428,7 +428,7 @@ quint32 QJSValue::toUInt() const \table \header \li Input Type \li Result \row \li Undefined \li An invalid QVariant. - \row \li Null \li An invalid QVariant. + \row \li Null \li A QVariant containing a null pointer (QMetaType::VoidStar). \row \li Boolean \li A QVariant containing the value of the boolean. \row \li Number \li A QVariant containing the value of the number. \row \li String \li A QVariant containing the value of the string. diff --git a/src/qml/qml/v8/qjsvalue_impl_p.h b/src/qml/qml/v8/qjsvalue_impl_p.h index fbddcfa5ba..8d22204843 100644 --- a/src/qml/qml/v8/qjsvalue_impl_p.h +++ b/src/qml/qml/v8/qjsvalue_impl_p.h @@ -281,7 +281,7 @@ QVariant QJSValuePrivate::toVariant() const case CNumber: return QVariant(u.m_number); case CNull: - return QVariant(); + return QVariant(QMetaType::VoidStar, 0); case CUndefined: return QVariant(); case JSValue: diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index 0cd5d0ad6c..9c570d756b 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -1061,7 +1061,9 @@ v8::Handle<v8::Value> createQmlObject(const v8::Arguments &args) QObject *obj = component.beginCreate(effectiveContext); if (obj) { - QQmlData::get(obj, true)->setImplicitDestructible(); + QQmlData::get(obj, true)->explicitIndestructibleSet = false; + QQmlData::get(obj)->indestructible = false; + obj->setParent(parentArg); @@ -1084,7 +1086,7 @@ v8::Handle<v8::Value> createQmlObject(const v8::Arguments &args) } /*! -\qmlmethod object Qt::createComponent(url, mode) +\qmlmethod object Qt::createComponent(url, mode, parent) Returns a \l Component object created using the QML file at the specified \a url, or \c null if an empty string was given. @@ -1099,6 +1101,9 @@ will be \c Component.Loading while it is loading. The status will change to \c Component.Ready if the component loads successfully, or \c Component.Error if loading fails. +If the optional \a parent parameter is given, it should refer to the object +that will become the parent for the created \l Component object. + Call \l {Component::createObject()}{Component.createObject()} on the returned component to create an object instance of the component. @@ -1114,7 +1119,8 @@ use \l{QML:Qt::createQmlObject()}{Qt.createQmlObject()}. v8::Handle<v8::Value> createComponent(const v8::Arguments &args) { const char *invalidArgs = "Qt.createComponent(): Invalid arguments"; - if (args.Length() < 1 || args.Length() > 2) + const char *invalidParent = "Qt.createComponent(): Invalid parent object"; + if (args.Length() < 1 || args.Length() > 3) V8THROW_ERROR(invalidArgs); QV8Engine *v8engine = V8ENGINE(); @@ -1131,21 +1137,46 @@ v8::Handle<v8::Value> createComponent(const v8::Arguments &args) return v8::Null(); QQmlComponent::CompilationMode compileMode = QQmlComponent::PreferSynchronous; - if (args.Length() == 2) { + + // Default to engine parent; this will be removed in the near future (QTBUG-24841) + QObject *parentArg = engine; + + unsigned consumedCount = 1; + if (args.Length() > 1) { + const v8::Local<v8::Value> &lastArg = args[args.Length()-1]; + + // The second argument could be the mode enum if (args[1]->IsInt32()) { int mode = args[1]->Int32Value(); if (mode != int(QQmlComponent::PreferSynchronous) && mode != int(QQmlComponent::Asynchronous)) V8THROW_ERROR(invalidArgs); compileMode = QQmlComponent::CompilationMode(mode); + consumedCount += 1; } else { - V8THROW_ERROR(invalidArgs); + // The second argument could be the parent only if there are exactly two args + if ((args.Length() != 2) || !(lastArg->IsObject() || lastArg->IsNull())) + V8THROW_ERROR(invalidArgs); + } + + if (consumedCount < args.Length()) { + if (lastArg->IsObject()) { + parentArg = v8engine->toQObject(lastArg); + if (!parentArg) + V8THROW_ERROR(invalidParent); + } else if (lastArg->IsNull()) { + parentArg = 0; + } else { + V8THROW_ERROR(invalidParent); + } } } QUrl url = context->resolvedUrl(QUrl(arg)); - QQmlComponent *c = new QQmlComponent(engine, url, compileMode, engine); + QQmlComponent *c = new QQmlComponent(engine, url, compileMode, parentArg); QQmlComponentPrivate::get(c)->creationContext = effectiveContext; - QQmlData::get(c, true)->setImplicitDestructible(); + QQmlData::get(c, true)->explicitIndestructibleSet = false; + QQmlData::get(c)->indestructible = false; + return v8engine->newQObject(c); } diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp index f0df025541..678f9aa3ee 100644 --- a/src/qml/qml/v8/qv8engine.cpp +++ b/src/qml/qml/v8/qv8engine.cpp @@ -1368,7 +1368,8 @@ v8::Handle<v8::Value> QV8Engine::variantToJS(const QVariant &value) } // Converts a JS value to a QVariant. -// Null, Undefined -> QVariant() (invalid) +// Undefined -> QVariant() (invalid) +// Null -> QVariant((void*)0) // Boolean -> QVariant(bool) // Number -> QVariant(double) // String -> QVariant(QString) @@ -1379,8 +1380,10 @@ v8::Handle<v8::Value> QV8Engine::variantToJS(const QVariant &value) QVariant QV8Engine::variantFromJS(v8::Handle<v8::Value> value) { Q_ASSERT(!value.IsEmpty()); - if (value->IsNull() || value->IsUndefined()) + if (value->IsUndefined()) return QVariant(); + if (value->IsNull()) + return QVariant(QMetaType::VoidStar, 0); if (value->IsBoolean()) return value->ToBoolean()->Value(); if (value->IsInt32()) |