diff options
Diffstat (limited to 'src/plugins')
77 files changed, 4705 insertions, 3603 deletions
diff --git a/src/plugins/qmltooling/packetprotocol/packetprotocol.pro b/src/plugins/qmltooling/packetprotocol/packetprotocol.pro new file mode 100644 index 0000000000..383e32b54e --- /dev/null +++ b/src/plugins/qmltooling/packetprotocol/packetprotocol.pro @@ -0,0 +1,13 @@ +TARGET = QtPacketProtocol +QT = core-private qml-private +CONFIG += static internal_module + +HEADERS = \ + qpacketprotocol_p.h \ + qpacket_p.h + +SOURCES = \ + qpacketprotocol.cpp \ + qpacket.cpp + +load(qt_module) diff --git a/src/plugins/qmltooling/packetprotocol/qpacket.cpp b/src/plugins/qmltooling/packetprotocol/qpacket.cpp new file mode 100644 index 0000000000..fab0a5b189 --- /dev/null +++ b/src/plugins/qmltooling/packetprotocol/qpacket.cpp @@ -0,0 +1,141 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qpacket_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \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 + int version = QDataStream::Qt_DefaultCompiledVersion; + QPacketProtocol protocol(...); + + QPacket myPacket(version); + myPacket << "Hello world!" << 123; + protocol.send(myPacket.data()); + \endcode + + As long as both ends of the connection are using the QPacketProtocol class + and the same data stream version, the data within this packet will be + delivered unfragmented at the other end, ready for extraction. + + \code + QByteArray greeting; + int count; + + QPacket myPacket(version, protocol.read()); + + myPacket >> greeting >> count; + \endcode + + Only packets constructed from raw byte arrays may be read from. Empty QPacket + instances 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(int version) +{ + buf.open(QIODevice::WriteOnly); + setDevice(&buf); + setVersion(version); +} + +/*! + Constructs a read-only packet. + */ +QPacket::QPacket(int version, const QByteArray &data) +{ + buf.setData(data); + buf.open(QIODevice::ReadOnly); + setDevice(&buf); + setVersion(version); +} + +/*! + Returns a reference to the raw packet data. + */ +const QByteArray &QPacket::data() const +{ + return buf.data(); +} + +/*! + Returns a copy of the raw packet data, with extra reserved space removed. + Mind that this triggers a deep copy. Use it if you anticipate the data to be detached soon anyway. + */ +QByteArray QPacket::squeezedData() const +{ + QByteArray ret = buf.data(); + ret.squeeze(); + return ret; +} + +/*! + Clears the packet, discarding any data. + */ +void QPacket::clear() +{ + buf.reset(); + QByteArray &buffer = buf.buffer(); + // Keep the old size to prevent unnecessary allocations + buffer.reserve(buffer.capacity()); + buffer.truncate(0); +} + +QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/packetprotocol/qpacket_p.h b/src/plugins/qmltooling/packetprotocol/qpacket_p.h new file mode 100644 index 0000000000..b6fda2411d --- /dev/null +++ b/src/plugins/qmltooling/packetprotocol/qpacket_p.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPACKET_H +#define QPACKET_H + +#include <QtCore/qdatastream.h> +#include <QtCore/qbuffer.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. +// + +QT_BEGIN_NAMESPACE + +class QPacket : public QDataStream +{ +public: + QPacket(int version); + explicit QPacket(int version, const QByteArray &ba); + const QByteArray &data() const; + QByteArray squeezedData() const; + void clear(); + +private: + void init(QIODevice::OpenMode mode); + QBuffer buf; +}; + +QT_END_NAMESPACE + +#endif // QPACKET_H diff --git a/src/plugins/qmltooling/packetprotocol/qpacketprotocol.cpp b/src/plugins/qmltooling/packetprotocol/qpacketprotocol.cpp new file mode 100644 index 0000000000..d20ddf9dc0 --- /dev/null +++ b/src/plugins/qmltooling/packetprotocol/qpacketprotocol.cpp @@ -0,0 +1,299 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qpacketprotocol_p.h" + +#include <QtCore/QElapsedTimer> +#include <private/qiodevice_p.h> +#include <private/qobject_p.h> + +QT_BEGIN_NAMESPACE + +static const 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 simply a QByteArray. The following example how to send + data using QPacketProtocol. + + \code + QTcpSocket socket; + // ... connect socket ... + + QPacketProtocol protocol(&socket); + + // Send a packet + QDataStream packet; + packet << "Hello world" << 123; + protocol.send(packet.data()); + \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 + QDataStream packet(protocol.read()); + p >> a >> b; + \endcode + + \ingroup io +*/ + +class QPacketProtocolPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QPacketProtocol) +public: + QPacketProtocolPrivate(QIODevice *dev); + + QList<qint64> sendingPackets; + QList<QByteArray> packets; + QByteArray inProgress; + qint32 inProgressSize; + 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(*(new QPacketProtocolPrivate(dev)), parent) +{ + Q_ASSERT(4 == sizeof(qint32)); + Q_ASSERT(dev); + + 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))); +} + +/*! + \fn void QPacketProtocol::send(const QByteArray &data) + + Transmit the \a packet. + */ +void QPacketProtocol::send(const QByteArray &data) +{ + Q_D(QPacketProtocol); + + if (data.isEmpty()) + return; // We don't send empty packets + qint64 sendSize = data.size() + sizeof(qint32); + + d->sendingPackets.append(sendSize); + qint32 sendSize32 = sendSize; + qint64 writeBytes = d->dev->write((char *)&sendSize32, sizeof(qint32)); + Q_UNUSED(writeBytes); + Q_ASSERT(writeBytes == sizeof(qint32)); + writeBytes = d->dev->write(data); + Q_ASSERT(writeBytes == data.size()); +} + +/*! + Returns the number of received packets yet to be read. + */ +qint64 QPacketProtocol::packetsAvailable() const +{ + Q_D(const QPacketProtocol); + return d->packets.count(); +} + +/*! + Return the next unread packet, or an empty QByteArray if no packets + are available. This method does NOT block. + */ +QByteArray QPacketProtocol::read() +{ + Q_D(QPacketProtocol); + return d->packets.isEmpty() ? QByteArray() : d->packets.takeFirst(); +} + +/*! + 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) +{ + Q_D(QPacketProtocol); + 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_subtract_from_timeout(msecs, stopWatch.elapsed()); + } while (true); +} + +/*! + Return the QIODevice passed to the QPacketProtocol constructor. +*/ +void QPacketProtocol::aboutToClose() +{ + Q_D(QPacketProtocol); + d->inProgress.clear(); + d->sendingPackets.clear(); + d->inProgressSize = -1; +} + +void QPacketProtocol::bytesWritten(qint64 bytes) +{ + Q_D(QPacketProtocol); + Q_ASSERT(!d->sendingPackets.isEmpty()); + + while (bytes) { + if (d->sendingPackets.at(0) > bytes) { + d->sendingPackets[0] -= bytes; + bytes = 0; + } else { + bytes -= d->sendingPackets.at(0); + d->sendingPackets.removeFirst(); + } + } +} + +void QPacketProtocol::readyToRead() +{ + Q_D(QPacketProtocol); + while (true) { + // Need to get trailing data + if (-1 == d->inProgressSize) { + // We need a size header of sizeof(qint32) + if (sizeof(qint32) > (uint)d->dev->bytesAvailable()) + return; + + // Read size header + int read = d->dev->read((char *)&d->inProgressSize, sizeof(qint32)); + Q_ASSERT(read == sizeof(qint32)); + Q_UNUSED(read); + + // Check sizing constraints + if (d->inProgressSize > MAX_PACKET_SIZE) { + QObject::disconnect(d->dev, SIGNAL(readyRead()), + this, SLOT(readyToRead())); + QObject::disconnect(d->dev, SIGNAL(aboutToClose()), + this, SLOT(aboutToClose())); + QObject::disconnect(d->dev, SIGNAL(bytesWritten(qint64)), + this, SLOT(bytesWritten(qint64))); + d->dev = 0; + emit invalidPacket(); + return; + } + + d->inProgressSize -= sizeof(qint32); + } else { + d->inProgress.append(d->dev->read(d->inProgressSize - d->inProgress.size())); + + if (d->inProgressSize == d->inProgress.size()) { + // Packet has arrived! + d->packets.append(d->inProgress); + d->inProgressSize = -1; + d->inProgress.clear(); + + d->waitingForPacket = false; + emit readyRead(); + } else + return; + } + } +} + +QPacketProtocolPrivate::QPacketProtocolPrivate(QIODevice *dev) : + inProgressSize(-1), waitingForPacket(false), dev(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. + */ + +QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/packetprotocol/qpacketprotocol_p.h b/src/plugins/qmltooling/packetprotocol/qpacketprotocol_p.h new file mode 100644 index 0000000000..8f95a081e9 --- /dev/null +++ b/src/plugins/qmltooling/packetprotocol/qpacketprotocol_p.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPACKETPROTOCOL_P_H +#define QPACKETPROTOCOL_P_H + +#include <QtCore/qobject.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. +// + +QT_BEGIN_NAMESPACE + +class QIODevice; + +class QPacketProtocolPrivate; +class QPacketProtocol : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QPacketProtocol) +public: + explicit QPacketProtocol(QIODevice *dev, QObject *parent = 0); + + void send(const QByteArray &data); + qint64 packetsAvailable() const; + QByteArray read(); + bool waitForReadyRead(int msecs = 3000); + +Q_SIGNALS: + void readyRead(); + void invalidPacket(); + +private Q_SLOTS: + void aboutToClose(); + void bytesWritten(qint64 bytes); + void readyToRead(); +}; + +QT_END_NAMESPACE + +#endif // QPACKETPROTOCOL_P_H diff --git a/src/plugins/qmltooling/qmldbg_debugger/qdebugmessageservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qdebugmessageservice.cpp index 6bccec08b1..31873f7915 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qdebugmessageservice.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qdebugmessageservice.cpp @@ -1,82 +1,85 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qdebugmessageservice.h" +#include "qqmldebugpacket.h" #include <private/qqmldebugconnector_p.h> -#include <QDataStream> - QT_BEGIN_NAMESPACE -const QString QDebugMessageService::s_key = QStringLiteral("DebugMessages"); - void DebugMessageHandler(QtMsgType type, const QMessageLogContext &ctxt, const QString &buf) { - QQmlDebugConnector::service<QDebugMessageService>()->sendDebugMessage(type, ctxt, buf); + QQmlDebugConnector::service<QDebugMessageServiceImpl>()->sendDebugMessage(type, ctxt, buf); } -QDebugMessageService::QDebugMessageService(QObject *parent) : - QQmlDebugService(s_key, 2, parent), oldMsgHandler(0), +QDebugMessageServiceImpl::QDebugMessageServiceImpl(QObject *parent) : + QDebugMessageService(2, parent), oldMsgHandler(0), prevState(QQmlDebugService::NotConnected) { // don't execute stateChanged() in parallel QMutexLocker lock(&initMutex); + timer.start(); if (state() == Enabled) { oldMsgHandler = qInstallMessageHandler(DebugMessageHandler); prevState = Enabled; } } -void QDebugMessageService::sendDebugMessage(QtMsgType type, +void QDebugMessageServiceImpl::sendDebugMessage(QtMsgType type, const QMessageLogContext &ctxt, const QString &buf) { //We do not want to alter the message handling mechanism //We just eavesdrop and forward the messages to a port //only if a client is connected to it. - QByteArray message; - QQmlDebugStream ws(&message, QIODevice::WriteOnly); + QQmlDebugPacket ws; ws << QByteArray("MESSAGE") << type << buf.toUtf8(); - ws << QString::fromLatin1(ctxt.file).toUtf8(); - ws << ctxt.line << QString::fromLatin1(ctxt.function).toUtf8(); + ws << QByteArray(ctxt.file) << ctxt.line << QByteArray(ctxt.function); + ws << QByteArray(ctxt.category) << timer.nsecsElapsed(); - emit messageToClient(name(), message); + emit messageToClient(name(), ws.data()); if (oldMsgHandler) (*oldMsgHandler)(type, ctxt, buf); } -void QDebugMessageService::stateChanged(State state) +void QDebugMessageServiceImpl::stateChanged(State state) { QMutexLocker lock(&initMutex); @@ -93,4 +96,10 @@ void QDebugMessageService::stateChanged(State state) prevState = state; } +void QDebugMessageServiceImpl::synchronizeTime(const QElapsedTimer &otherTimer) +{ + QMutexLocker lock(&initMutex); + timer = otherTimer; +} + QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_debugger/qdebugmessageservice.h b/src/plugins/qmltooling/qmldbg_debugger/qdebugmessageservice.h index c0dc41bcd0..c25e756c2d 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qdebugmessageservice.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qdebugmessageservice.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -45,36 +51,35 @@ // We mean it. // -#include <private/qqmldebugservice_p.h> +#include <private/qqmldebugserviceinterfaces_p.h> #include <QtCore/qlogging.h> #include <QtCore/qmutex.h> +#include <QtCore/qelapsedtimer.h> QT_BEGIN_NAMESPACE class QDebugMessageServicePrivate; -class QDebugMessageService : public QQmlDebugService +class QDebugMessageServiceImpl : public QDebugMessageService { Q_OBJECT public: - QDebugMessageService(QObject *parent = 0); + QDebugMessageServiceImpl(QObject *parent = 0); - void sendDebugMessage(QtMsgType type, const QMessageLogContext &ctxt, - const QString &buf); + void sendDebugMessage(QtMsgType type, const QMessageLogContext &ctxt, const QString &buf); + void synchronizeTime(const QElapsedTimer &otherTimer); protected: - static const QString s_key; - void stateChanged(State); private: - friend class QQmlDebugConnector; friend class QQmlDebuggerServiceFactory; QtMessageHandler oldMsgHandler; QQmlDebugService::State prevState; QMutex initMutex; + QElapsedTimer timer; }; QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro b/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro index dc923b2350..27b3a5b513 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro +++ b/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro @@ -1,5 +1,5 @@ TARGET = qmldbg_debugger -QT = qml-private core-private +QT = qml-private core-private packetprotocol-private SOURCES += \ $$PWD/qdebugmessageservice.cpp \ @@ -8,19 +8,24 @@ SOURCES += \ $$PWD/qqmlnativedebugservice.cpp \ $$PWD/qqmlwatcher.cpp \ $$PWD/qv4debugservice.cpp \ + $$PWD/qv4debugger.cpp \ $$PWD/qv4debuggeragent.cpp \ - $$PWD/qv4datacollector.cpp + $$PWD/qv4datacollector.cpp \ + $$PWD/qv4debugjob.cpp HEADERS += \ $$PWD/../shared/qqmlconfigurabledebugservice.h \ + $$PWD/../shared/qqmldebugpacket.h \ $$PWD/qdebugmessageservice.h \ $$PWD/qqmldebuggerservicefactory.h \ $$PWD/qqmlenginedebugservice.h \ $$PWD/qqmlnativedebugservice.h \ $$PWD/qqmlwatcher.h \ $$PWD/qv4debugservice.h \ + $$PWD/qv4debugger.h \ $$PWD/qv4debuggeragent.h \ - $$PWD/qv4datacollector.h + $$PWD/qv4datacollector.h \ + $$PWD/qv4debugjob.h INCLUDEPATH += $$PWD \ $$PWD/../shared diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp index f379352cfa..ca3f07323d 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -42,8 +48,8 @@ QT_BEGIN_NAMESPACE QQmlDebugService *QQmlDebuggerServiceFactory::create(const QString &key) { - if (key == QDebugMessageService::s_key) - return new QDebugMessageService(this); + if (key == QDebugMessageServiceImpl::s_key) + return new QDebugMessageServiceImpl(this); if (key == QQmlEngineDebugServiceImpl::s_key) return new QQmlEngineDebugServiceImpl(this); diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.h b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.h index 2c7509ba12..99d6679833 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp index 8f53dc6d50..ff4e30835d 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -33,6 +39,7 @@ #include "qqmlenginedebugservice.h" #include "qqmlwatcher.h" +#include "qqmldebugpacket.h" #include <private/qqmldebugstatesdelegate_p.h> #include <private/qqmlboundsignal_p.h> @@ -89,8 +96,7 @@ QDataStream &operator<<(QDataStream &ds, ds << (int)data.type << data.name; // check first whether the data can be saved // (otherwise we assert in QVariant::operator<<) - QByteArray buffer; - QDataStream fakeStream(&buffer, QIODevice::WriteOnly); + QQmlDebugPacket fakeStream; if (QMetaType::save(fakeStream, data.value.type(), data.value.constData())) ds << data.value; else @@ -427,7 +433,7 @@ QList<QObject*> QQmlEngineDebugServiceImpl::objectForLocationInfo(const QString const QHash<int, QObject *> &hash = objectsForIds(); for (QHash<int, QObject *>::ConstIterator i = hash.constBegin(); i != hash.constEnd(); ++i) { QQmlData *ddata = QQmlData::get(i.value()); - if (ddata && ddata->outerContext) { + if (ddata && ddata->outerContext && ddata->outerContext->isValid()) { if (QFileInfo(ddata->outerContext->urlString()).fileName() == filename && ddata->lineNumber == lineNumber && ddata->columnNumber >= columnNumber) { @@ -440,21 +446,20 @@ QList<QObject*> QQmlEngineDebugServiceImpl::objectForLocationInfo(const QString void QQmlEngineDebugServiceImpl::processMessage(const QByteArray &message) { - QQmlDebugStream ds(message); + QQmlDebugPacket ds(message); QByteArray type; int queryId; ds >> type >> queryId; - QByteArray reply; - QQmlDebugStream rs(&reply, QIODevice::WriteOnly); + QQmlDebugPacket rs; if (type == "LIST_ENGINES") { rs << QByteArray("LIST_ENGINES_R"); rs << queryId << m_engines.count(); for (int ii = 0; ii < m_engines.count(); ++ii) { - QQmlEngine *engine = m_engines.at(ii); + QJSEngine *engine = m_engines.at(ii); QString engineName = engine->objectName(); int engineId = QQmlDebugService::idForObject(engine); @@ -617,7 +622,7 @@ void QQmlEngineDebugServiceImpl::processMessage(const QByteArray &message) rs << QByteArray("SET_METHOD_BODY_R") << queryId << ok; } - emit messageToClient(name(), reply); + emit messageToClient(name(), rs.data()); } bool QQmlEngineDebugServiceImpl::setBinding(int objectId, @@ -678,11 +683,13 @@ bool QQmlEngineDebugServiceImpl::resetBinding(int objectId, const QString &prope QQmlContext *context = qmlContext(object); if (object && context) { - QString parentProperty = propertyName; - if (propertyName.indexOf(QLatin1Char('.')) != -1) - parentProperty = propertyName.left(propertyName.indexOf(QLatin1Char('.'))); + QStringRef parentPropertyRef(&propertyName); + const int idx = parentPropertyRef.indexOf(QLatin1Char('.')); + if (idx != -1) + parentPropertyRef = parentPropertyRef.left(idx); - if (object->property(parentProperty.toLatin1()).isValid()) { + const QByteArray parentProperty = parentPropertyRef.toLatin1(); + if (object->property(parentProperty).isValid()) { QQmlProperty property(object, propertyName); QQmlPropertyPrivate::removeBinding(property); if (property.isResettable()) { @@ -695,7 +702,7 @@ bool QQmlEngineDebugServiceImpl::resetBinding(int objectId, const QString &prope // overwrite with default value if (QQmlType *objType = QQmlMetaType::qmlType(object->metaObject())) { if (QObject *emptyObject = objType->create()) { - if (emptyObject->property(parentProperty.toLatin1()).isValid()) { + if (emptyObject->property(parentProperty).isValid()) { QVariant defaultValue = QQmlProperty(emptyObject, propertyName).read(); if (defaultValue.isValid()) { setBinding(objectId, propertyName, defaultValue, true); @@ -769,15 +776,12 @@ bool QQmlEngineDebugServiceImpl::setMethodBody(int objectId, const QString &meth void QQmlEngineDebugServiceImpl::propertyChanged(int id, int objectId, const QMetaProperty &property, const QVariant &value) { - QByteArray reply; - QQmlDebugStream rs(&reply, QIODevice::WriteOnly); - + QQmlDebugPacket rs; rs << QByteArray("UPDATE_WATCH") << id << objectId << QByteArray(property.name()) << valueContents(value); - - emit messageToClient(name(), reply); + emit messageToClient(name(), rs.data()); } -void QQmlEngineDebugServiceImpl::engineAboutToBeAdded(QQmlEngine *engine) +void QQmlEngineDebugServiceImpl::engineAboutToBeAdded(QJSEngine *engine) { Q_ASSERT(engine); Q_ASSERT(!m_engines.contains(engine)); @@ -786,7 +790,7 @@ void QQmlEngineDebugServiceImpl::engineAboutToBeAdded(QQmlEngine *engine) emit attachedToEngine(engine); } -void QQmlEngineDebugServiceImpl::engineAboutToBeRemoved(QQmlEngine *engine) +void QQmlEngineDebugServiceImpl::engineAboutToBeRemoved(QJSEngine *engine) { Q_ASSERT(engine); Q_ASSERT(m_engines.contains(engine)); @@ -795,7 +799,7 @@ void QQmlEngineDebugServiceImpl::engineAboutToBeRemoved(QQmlEngine *engine) emit detachedFromEngine(engine); } -void QQmlEngineDebugServiceImpl::objectCreated(QQmlEngine *engine, QObject *object) +void QQmlEngineDebugServiceImpl::objectCreated(QJSEngine *engine, QObject *object) { Q_ASSERT(engine); Q_ASSERT(m_engines.contains(engine)); @@ -804,12 +808,11 @@ void QQmlEngineDebugServiceImpl::objectCreated(QQmlEngine *engine, QObject *obje int objectId = QQmlDebugService::idForObject(object); int parentId = QQmlDebugService::idForObject(object->parent()); - QByteArray reply; - QQmlDebugStream rs(&reply, QIODevice::WriteOnly); + QQmlDebugPacket rs; //unique queryId -1 rs << QByteArray("OBJECT_CREATED") << -1 << engineId << objectId << parentId; - emit messageToClient(name(), reply); + emit messageToClient(name(), rs.data()); } void QQmlEngineDebugServiceImpl::setStatesDelegate(QQmlDebugStatesDelegate *delegate) diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.h b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.h index 68cb420cc0..cb75a63850 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -89,9 +95,9 @@ public: bool hasNotifySignal; }; - void engineAboutToBeAdded(QQmlEngine *) Q_DECL_OVERRIDE; - void engineAboutToBeRemoved(QQmlEngine *) Q_DECL_OVERRIDE; - void objectCreated(QQmlEngine *, QObject *) Q_DECL_OVERRIDE; + void engineAboutToBeAdded(QJSEngine *) Q_DECL_OVERRIDE; + void engineAboutToBeRemoved(QJSEngine *) Q_DECL_OVERRIDE; + void objectCreated(QJSEngine *, QObject *) Q_DECL_OVERRIDE; void setStatesDelegate(QQmlDebugStatesDelegate *) Q_DECL_OVERRIDE; @@ -120,7 +126,7 @@ private: QList<QObject *> objectForLocationInfo(const QString &filename, int lineNumber, int columnNumber); - QList<QQmlEngine *> m_engines; + QList<QJSEngine *> m_engines; QQmlWatcher *m_watch; QQmlDebugStatesDelegate *m_statesDelegate; }; diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp index 24d2a82413..e3b2bc0870 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.cpp @@ -1,37 +1,44 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qqmlnativedebugservice.h" +#include "qqmldebugpacket.h" #include <private/qqmldebugconnector_p.h> #include <private/qv4debugging_p.h> @@ -46,8 +53,7 @@ #include <private/qv4isel_moth_p.h> #include <private/qqmldebugserviceinterfaces_p.h> -#include <qqmlengine.h> - +#include <QtQml/qjsengine.h> #include <QtCore/qjsonarray.h> #include <QtCore/qjsondocument.h> #include <QtCore/qjsonobject.h> @@ -313,16 +319,15 @@ void NativeDebugger::handleCommand(QJsonObject *response, const QString &cmd, static QString encodeContext(QV4::ExecutionContext *executionContext) { - QByteArray ba; - QDataStream ds(&ba, QIODevice::WriteOnly); + QQmlDebugPacket ds; ds << quintptr(executionContext); - return QString::fromLatin1(ba.toHex()); + return QString::fromLatin1(ds.data().toHex()); } static void decodeContext(const QString &context, QV4::ExecutionContext **executionContext) { quintptr rawContext; - QDataStream ds(QByteArray::fromHex(context.toLatin1())); + QQmlDebugPacket ds(QByteArray::fromHex(context.toLatin1())); ds >> rawContext; *executionContext = reinterpret_cast<QV4::ExecutionContext *>(rawContext); } @@ -699,7 +704,7 @@ bool NativeDebugger::reallyHitTheBreakPoint(const QV4::Function *function, int l const BreakPoint &bp = m_service->m_breakHandler->m_breakPoints.at(i); if (bp.lineNumber == lineNumber) { const QString fileName = function->sourceFile(); - const QString base = fileName.mid(fileName.lastIndexOf('/') + 1); + const QStringRef base = fileName.midRef(fileName.lastIndexOf('/') + 1); if (bp.fileName.endsWith(base)) { if (bp.condition.isEmpty() || checkCondition(bp.condition)) { BreakPoint &mbp = m_service->m_breakHandler->m_breakPoints[i]; @@ -724,7 +729,7 @@ QQmlNativeDebugServiceImpl::~QQmlNativeDebugServiceImpl() delete m_breakHandler; } -void QQmlNativeDebugServiceImpl::engineAboutToBeAdded(QQmlEngine *engine) +void QQmlNativeDebugServiceImpl::engineAboutToBeAdded(QJSEngine *engine) { TRACE_PROTOCOL("Adding engine" << engine); if (engine) { @@ -741,7 +746,7 @@ void QQmlNativeDebugServiceImpl::engineAboutToBeAdded(QQmlEngine *engine) QQmlDebugService::engineAboutToBeAdded(engine); } -void QQmlNativeDebugServiceImpl::engineAboutToBeRemoved(QQmlEngine *engine) +void QQmlNativeDebugServiceImpl::engineAboutToBeRemoved(QJSEngine *engine) { TRACE_PROTOCOL("Removing engine" << engine); if (engine) { diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.h b/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.h index 9d0780a203..8015513f9e 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlnativedebugservice.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -68,14 +74,14 @@ class QQmlNativeDebugServiceImpl : public QQmlNativeDebugService public: QQmlNativeDebugServiceImpl(QObject *parent); - ~QQmlNativeDebugServiceImpl(); + ~QQmlNativeDebugServiceImpl() Q_DECL_OVERRIDE; - void engineAboutToBeAdded(QQmlEngine *engine); - void engineAboutToBeRemoved(QQmlEngine *engine); + void engineAboutToBeAdded(QJSEngine *engine) Q_DECL_OVERRIDE; + void engineAboutToBeRemoved(QJSEngine *engine) Q_DECL_OVERRIDE; - void stateAboutToBeChanged(State state); + void stateAboutToBeChanged(State state) Q_DECL_OVERRIDE; - void messageReceived(const QByteArray &message); + void messageReceived(const QByteArray &message) Q_DECL_OVERRIDE; void emitAsynchronousMessageToClient(const QJsonObject &message); diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.cpp index 9f9a6eb33b..392080dd51 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.cpp @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.h b/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.h index 329aee77d2..4b304a6087 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp index adba1dbdd9..96f60b24bb 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp @@ -1,37 +1,45 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qv4datacollector.h" +#include "qv4debugger.h" +#include "qv4debugjob.h" #include <private/qv4script_p.h> #include <private/qv4string_p.h> @@ -39,7 +47,11 @@ #include <private/qv4identifier_p.h> #include <private/qv4runtime_p.h> +#include <private/qqmlcontext_p.h> +#include <private/qqmlengine_p.h> + #include <QtCore/qjsonarray.h> +#include <QtCore/qjsonobject.h> QT_BEGIN_NAMESPACE @@ -93,17 +105,13 @@ int QV4DataCollector::encodeScopeType(QV4::Heap::ExecutionContext::ContextType s switch (scopeType) { case QV4::Heap::ExecutionContext::Type_GlobalContext: return 0; - break; case QV4::Heap::ExecutionContext::Type_CatchContext: return 4; - break; case QV4::Heap::ExecutionContext::Type_WithContext: return 2; - break; case QV4::Heap::ExecutionContext::Type_SimpleCallContext: case QV4::Heap::ExecutionContext::Type_CallContext: return 1; - break; case QV4::Heap::ExecutionContext::Type_QmlContext: default: return -1; @@ -112,17 +120,13 @@ int QV4DataCollector::encodeScopeType(QV4::Heap::ExecutionContext::ContextType s QV4DataCollector::QV4DataCollector(QV4::ExecutionEngine *engine) : m_engine(engine) { - values.set(engine, engine->newArrayObject()); -} - -QV4DataCollector::~QV4DataCollector() -{ + m_values.set(engine, engine->newArrayObject()); } QV4DataCollector::Ref QV4DataCollector::collect(const QV4::ScopedValue &value) { Ref ref = addRef(value); - collectedRefs.append(ref); + m_collectedRefs.append(ref); return ref; } @@ -210,8 +214,8 @@ QV4DataCollector::Ref QV4DataCollector::addFunctionRef(const QString &functionNa dict.insert(QStringLiteral("handle"), qint64(ref)); dict.insert(QStringLiteral("type"), QStringLiteral("function")); dict.insert(QStringLiteral("name"), functionName); - specialRefs.insert(ref, dict); - collectedRefs.append(ref); + m_specialRefs.insert(ref, dict); + m_collectedRefs.append(ref); return ref; } @@ -224,8 +228,8 @@ QV4DataCollector::Ref QV4DataCollector::addScriptRef(const QString &scriptName) dict.insert(QStringLiteral("handle"), qint64(ref)); dict.insert(QStringLiteral("type"), QStringLiteral("script")); dict.insert(QStringLiteral("name"), scriptName); - specialRefs.insert(ref, dict); - collectedRefs.append(ref); + m_specialRefs.insert(ref, dict); + m_collectedRefs.append(ref); return ref; } @@ -233,7 +237,7 @@ QV4DataCollector::Ref QV4DataCollector::addScriptRef(const QString &scriptName) bool QV4DataCollector::isValidRef(QV4DataCollector::Ref ref) const { QV4::Scope scope(engine()); - QV4::ScopedObject array(scope, values.value()); + QV4::ScopedObject array(scope, m_values.value()); return ref < array->getLength(); } @@ -268,14 +272,14 @@ bool QV4DataCollector::collectScope(QJsonObject *dict, int frameNr, int scopeNr) QV4::ScopedObject scopeObject(scope, engine()->newObject()); - Q_ASSERT(names.size() == collectedRefs.size()); - for (int i = 0, ei = collectedRefs.size(); i != ei; ++i) + Q_ASSERT(names.size() == m_collectedRefs.size()); + for (int i = 0, ei = m_collectedRefs.size(); i != ei; ++i) scopeObject->put(engine(), names.at(i), - QV4::Value::fromReturnedValue(getValue(collectedRefs.at(i)))); + QV4::Value::fromReturnedValue(getValue(m_collectedRefs.at(i)))); Ref scopeObjectRef = addRef(scopeObject); dict->insert(QStringLiteral("ref"), qint64(scopeObjectRef)); - collectedRefs.append(scopeObjectRef); + m_collectedRefs.append(scopeObjectRef); return true; } @@ -328,6 +332,7 @@ QJsonObject QV4DataCollector::buildFrame(const QV4::StackFrame &stackFrame, int scope[QLatin1String("type")] = type; scopes.push_back(scope); } + frame[QLatin1String("scopes")] = scopes; return frame; @@ -336,18 +341,25 @@ QJsonObject QV4DataCollector::buildFrame(const QV4::StackFrame &stackFrame, int QJsonArray QV4DataCollector::flushCollectedRefs() { QJsonArray refs; - std::sort(collectedRefs.begin(), collectedRefs.end()); - for (int i = 0, ei = collectedRefs.size(); i != ei; ++i) { - QV4DataCollector::Ref ref = collectedRefs.at(i); - if (i > 0 && ref == collectedRefs.at(i - 1)) + std::sort(m_collectedRefs.begin(), m_collectedRefs.end()); + for (int i = 0, ei = m_collectedRefs.size(); i != ei; ++i) { + QV4DataCollector::Ref ref = m_collectedRefs.at(i); + if (i > 0 && ref == m_collectedRefs.at(i - 1)) continue; refs.append(lookupRef(ref)); } - collectedRefs.clear(); + m_collectedRefs.clear(); return refs; } +void QV4DataCollector::clear() +{ + m_values.set(engine(), engine()->newArrayObject()); + m_collectedRefs.clear(); + m_specialRefs.clear(); +} + QV4DataCollector::Ref QV4DataCollector::addRef(QV4::Value value, bool deduplicate) { class ExceptionStateSaver @@ -368,10 +380,10 @@ QV4DataCollector::Ref QV4DataCollector::addRef(QV4::Value value, bool deduplicat // if we wouldn't do this, the putIndexed won't work. ExceptionStateSaver resetExceptionState(engine()); QV4::Scope scope(engine()); - QV4::ScopedObject array(scope, values.value()); + QV4::ScopedObject array(scope, m_values.value()); if (deduplicate) { for (Ref i = 0; i < array->getLength(); ++i) { - if (array->getIndexed(i) == value.rawValue() && !specialRefs.contains(i)) + if (array->getIndexed(i) == value.rawValue() && !m_specialRefs.contains(i)) return i; } } @@ -384,15 +396,15 @@ QV4DataCollector::Ref QV4DataCollector::addRef(QV4::Value value, bool deduplicat QV4::ReturnedValue QV4DataCollector::getValue(Ref ref) { QV4::Scope scope(engine()); - QV4::ScopedObject array(scope, values.value()); + QV4::ScopedObject array(scope, m_values.value()); Q_ASSERT(ref < array->getLength()); return array->getIndexed(ref, Q_NULLPTR); } bool QV4DataCollector::lookupSpecialRef(Ref ref, QJsonObject *dict) { - SpecialRefs::const_iterator it = specialRefs.find(ref); - if (it == specialRefs.end()) + SpecialRefs::const_iterator it = m_specialRefs.constFind(ref); + if (it == m_specialRefs.cend()) return false; *dict = it.value(); @@ -428,154 +440,11 @@ QJsonObject QV4DataCollector::collectAsJson(const QString &name, const QV4::Scop if (value->isManaged() && !value->isString()) { Ref ref = addRef(value); dict.insert(QStringLiteral("ref"), qint64(ref)); - collectedRefs.append(ref); + m_collectedRefs.append(ref); } collectProperty(value, engine(), dict); return dict; } -BacktraceJob::BacktraceJob(QV4DataCollector *collector, int fromFrame, int toFrame) : - CollectJob(collector), fromFrame(fromFrame), toFrame(toFrame) -{ -} - -void BacktraceJob::run() -{ - QJsonArray frameArray; - QVector<QV4::StackFrame> frames = collector->engine()->stackTrace(toFrame); - for (int i = fromFrame; i < toFrame && i < frames.size(); ++i) - frameArray.push_back(collector->buildFrame(frames[i], i)); - if (frameArray.isEmpty()) { - result.insert(QStringLiteral("totalFrames"), 0); - } else { - result.insert(QStringLiteral("fromFrame"), fromFrame); - result.insert(QStringLiteral("toFrame"), fromFrame + frameArray.size()); - result.insert(QStringLiteral("frames"), frameArray); - } - collectedRefs = collector->flushCollectedRefs(); -} - -FrameJob::FrameJob(QV4DataCollector *collector, int frameNr) : - CollectJob(collector), frameNr(frameNr), success(false) -{ -} - -void FrameJob::run() -{ - QVector<QV4::StackFrame> frames = collector->engine()->stackTrace(frameNr + 1); - if (frameNr >= frames.length()) { - success = false; - } else { - result = collector->buildFrame(frames[frameNr], frameNr); - collectedRefs = collector->flushCollectedRefs(); - success = true; - } -} - -bool FrameJob::wasSuccessful() const -{ - return success; -} - -ScopeJob::ScopeJob(QV4DataCollector *collector, int frameNr, int scopeNr) : - CollectJob(collector), frameNr(frameNr), scopeNr(scopeNr), success(false) -{ -} - -void ScopeJob::run() -{ - QJsonObject object; - success = collector->collectScope(&object, frameNr, scopeNr); - - if (success) { - QVector<QV4::Heap::ExecutionContext::ContextType> scopeTypes = - collector->getScopeTypes(frameNr); - result[QLatin1String("type")] = QV4DataCollector::encodeScopeType(scopeTypes[scopeNr]); - } else { - result[QLatin1String("type")] = -1; - } - result[QLatin1String("index")] = scopeNr; - result[QLatin1String("frameIndex")] = frameNr; - result[QLatin1String("object")] = object; - collectedRefs = collector->flushCollectedRefs(); -} - -bool ScopeJob::wasSuccessful() const -{ - return success; -} - -ValueLookupJob::ValueLookupJob(const QJsonArray &handles, QV4DataCollector *collector) : - CollectJob(collector), handles(handles) {} - -void ValueLookupJob::run() -{ - foreach (const QJsonValue &handle, handles) { - QV4DataCollector::Ref ref = handle.toInt(); - if (!collector->isValidRef(ref)) { - exception = QString::fromLatin1("Invalid Ref: %1").arg(ref); - break; - } - result[QString::number(ref)] = collector->lookupRef(ref); - } - collectedRefs = collector->flushCollectedRefs(); -} - -const QString &ValueLookupJob::exceptionMessage() const -{ - return exception; -} - -ExpressionEvalJob::ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, - const QString &expression, - QV4DataCollector *collector) - : JavaScriptJob(engine, frameNr, expression) - , collector(collector) -{ -} - -void ExpressionEvalJob::handleResult(QV4::ScopedValue &value) -{ - if (hasExeption()) - exception = value->toQStringNoThrow(); - result = collector->lookupRef(collector->collect(value)); - collectedRefs = collector->flushCollectedRefs(); -} - -const QString &ExpressionEvalJob::exceptionMessage() const -{ - return exception; -} - -const QJsonObject &ExpressionEvalJob::returnValue() const -{ - return result; -} - -const QJsonArray &ExpressionEvalJob::refs() const -{ - return collectedRefs; -} - -GatherSourcesJob::GatherSourcesJob(QV4::ExecutionEngine *engine, int seq) - : engine(engine) - , seq(seq) -{} - -void GatherSourcesJob::run() -{ - QStringList sources; - - foreach (QV4::CompiledData::CompilationUnit *unit, engine->compilationUnits) { - QString fileName = unit->fileName(); - if (!fileName.isEmpty()) - sources.append(fileName); - } - - QV4::Debugging::V4Debugger *debugger - = static_cast<QV4::Debugging::V4Debugger *>(engine->debugger); - emit debugger->sourcesCollected(debugger, sources, seq); -} - QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h index acc3a6022e..fd6356f22e 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -35,40 +41,44 @@ #define QV4DATACOLLECTOR_H #include <private/qv4engine_p.h> -#include <private/qv4debugging_p.h> +#include <private/qv4persistent_p.h> + +#include <QtCore/QJsonObject> +#include <QtCore/QJsonArray> #include <QtCore/QJsonObject> #include <QtCore/QJsonArray> QT_BEGIN_NAMESPACE +class QV4Debugger; class QV4DataCollector { public: typedef uint Ref; typedef QVector<uint> Refs; - static const Ref s_invalidRef; - QV4::CallContext *findContext(int frame); static QV4::Heap::CallContext *findScope(QV4::ExecutionContext *ctxt, int scope); - QVector<QV4::Heap::ExecutionContext::ContextType> getScopeTypes(int frame); static int encodeScopeType(QV4::Heap::ExecutionContext::ContextType scopeType); + QVector<QV4::Heap::ExecutionContext::ContextType> getScopeTypes(int frame); + QV4::CallContext *findContext(int frame); + QV4DataCollector(QV4::ExecutionEngine *engine); - ~QV4DataCollector(); Ref collect(const QV4::ScopedValue &value); - bool isValidRef(Ref ref) const; - QJsonObject lookupRef(Ref ref); - Ref addFunctionRef(const QString &functionName); Ref addScriptRef(const QString &scriptName); + bool isValidRef(Ref ref) const; + QJsonObject lookupRef(Ref ref); + bool collectScope(QJsonObject *dict, int frameNr, int scopeNr); QJsonObject buildFrame(const QV4::StackFrame &stackFrame, int frameNr); QV4::ExecutionEngine *engine() const { return m_engine; } QJsonArray flushCollectedRefs(); + void clear(); private: Ref addRef(QV4::Value value, bool deduplicate = true); @@ -80,91 +90,10 @@ private: void collectArgumentsInContext(); QV4::ExecutionEngine *m_engine; - Refs collectedRefs; - QV4::PersistentValue values; + Refs m_collectedRefs; + QV4::PersistentValue m_values; typedef QHash<Ref, QJsonObject> SpecialRefs; - SpecialRefs specialRefs; -}; - -class CollectJob : public QV4::Debugging::V4Debugger::Job -{ -protected: - QV4DataCollector *collector; - QJsonObject result; - QJsonArray collectedRefs; -public: - CollectJob(QV4DataCollector *collector) : collector(collector) {} - const QJsonObject &returnValue() const { return result; } - const QJsonArray &refs() const { return collectedRefs; } -}; - -class BacktraceJob: public CollectJob -{ - int fromFrame; - int toFrame; -public: - BacktraceJob(QV4DataCollector *collector, int fromFrame, int toFrame); - void run(); -}; - -class FrameJob: public CollectJob -{ - int frameNr; - bool success; - -public: - FrameJob(QV4DataCollector *collector, int frameNr); - void run(); - bool wasSuccessful() const; -}; - -class ScopeJob: public CollectJob -{ - int frameNr; - int scopeNr; - bool success; - -public: - ScopeJob(QV4DataCollector *collector, int frameNr, int scopeNr); - void run(); - bool wasSuccessful() const; -}; - -class ValueLookupJob: public CollectJob -{ - const QJsonArray handles; - QString exception; - -public: - ValueLookupJob(const QJsonArray &handles, QV4DataCollector *collector); - void run(); - const QString &exceptionMessage() const; -}; - -class ExpressionEvalJob: public QV4::Debugging::V4Debugger::JavaScriptJob -{ - QV4DataCollector *collector; - QString exception; - QJsonObject result; - QJsonArray collectedRefs; - -public: - ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, const QString &expression, - QV4DataCollector *collector); - virtual void handleResult(QV4::ScopedValue &value); - const QString &exceptionMessage() const; - const QJsonObject &returnValue() const; - const QJsonArray &refs() const; -}; - -class GatherSourcesJob: public QV4::Debugging::V4Debugger::Job -{ - QV4::ExecutionEngine *engine; - const int seq; - -public: - GatherSourcesJob(QV4::ExecutionEngine *engine, int seq); - void run(); + SpecialRefs m_specialRefs; }; QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp new file mode 100644 index 0000000000..53f2eab5ff --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp @@ -0,0 +1,328 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qv4debugger.h" +#include "qv4debugjob.h" +#include "qv4datacollector.h" + +#include <private/qv4scopedvalue_p.h> +#include <private/qv4script_p.h> +#include <private/qqmlcontext_p.h> +#include <private/qqmlengine_p.h> + +QT_BEGIN_NAMESPACE + +QV4Debugger::BreakPoint::BreakPoint(const QString &fileName, int line) + : fileName(fileName), lineNumber(line) +{} + +inline uint qHash(const QV4Debugger::BreakPoint &b, uint seed = 0) Q_DECL_NOTHROW +{ + return qHash(b.fileName, seed) ^ b.lineNumber; +} + +inline bool operator==(const QV4Debugger::BreakPoint &a, + const QV4Debugger::BreakPoint &b) +{ + return a.lineNumber == b.lineNumber && a.fileName == b.fileName; +} + +QV4Debugger::QV4Debugger(QV4::ExecutionEngine *engine) + : m_engine(engine) + , m_state(Running) + , m_stepping(NotStepping) + , m_pauseRequested(false) + , m_haveBreakPoints(false) + , m_breakOnThrow(false) + , m_returnedValue(engine, QV4::Primitive::undefinedValue()) + , m_gatherSources(0) + , m_runningJob(0) + , m_collector(engine) +{ + static int debuggerId = qRegisterMetaType<QV4Debugger*>(); + static int pauseReasonId = qRegisterMetaType<QV4Debugger::PauseReason>(); + Q_UNUSED(debuggerId); + Q_UNUSED(pauseReasonId); +} + +QV4::ExecutionEngine *QV4Debugger::engine() const +{ + return m_engine; +} + +const QV4DataCollector *QV4Debugger::collector() const +{ + return &m_collector; +} + +QV4DataCollector *QV4Debugger::collector() +{ + return &m_collector; +} + +void QV4Debugger::pause() +{ + QMutexLocker locker(&m_lock); + if (m_state == Paused) + return; + m_pauseRequested = true; +} + +void QV4Debugger::resume(Speed speed) +{ + QMutexLocker locker(&m_lock); + if (m_state != Paused) + return; + + if (!m_returnedValue.isUndefined()) + m_returnedValue.set(m_engine, QV4::Encode::undefined()); + + m_currentContext.set(m_engine, *m_engine->currentContext); + m_stepping = speed; + m_runningCondition.wakeAll(); +} + +QV4Debugger::State QV4Debugger::state() const +{ + return m_state; +} + +void QV4Debugger::addBreakPoint(const QString &fileName, int lineNumber, const QString &condition) +{ + QMutexLocker locker(&m_lock); + m_breakPoints.insert(BreakPoint(fileName.mid(fileName.lastIndexOf('/') + 1), + lineNumber), condition); + m_haveBreakPoints = true; +} + +void QV4Debugger::removeBreakPoint(const QString &fileName, int lineNumber) +{ + QMutexLocker locker(&m_lock); + m_breakPoints.remove(BreakPoint(fileName.mid(fileName.lastIndexOf('/') + 1), + lineNumber)); + m_haveBreakPoints = !m_breakPoints.isEmpty(); +} + +void QV4Debugger::setBreakOnThrow(bool onoff) +{ + QMutexLocker locker(&m_lock); + + m_breakOnThrow = onoff; +} + +void QV4Debugger::clearPauseRequest() +{ + QMutexLocker locker(&m_lock); + m_pauseRequested = false; +} + +QV4Debugger::ExecutionState QV4Debugger::currentExecutionState() const +{ + ExecutionState state; + state.fileName = getFunction()->sourceFile(); + state.lineNumber = engine()->current->lineNumber; + + return state; +} + +bool QV4Debugger::pauseAtNextOpportunity() const { + return m_pauseRequested || m_haveBreakPoints || m_gatherSources || m_stepping >= StepOver; +} + +QVector<QV4::StackFrame> QV4Debugger::stackTrace(int frameLimit) const +{ + return m_engine->stackTrace(frameLimit); +} + +void QV4Debugger::maybeBreakAtInstruction() +{ + if (m_runningJob) // do not re-enter when we're doing a job for the debugger. + return; + + QMutexLocker locker(&m_lock); + + if (m_gatherSources) { + m_gatherSources->run(); + delete m_gatherSources; + m_gatherSources = 0; + } + + switch (m_stepping) { + case StepOver: + if (m_currentContext.asManaged()->d() != m_engine->current) + break; + // fall through + case StepIn: + pauseAndWait(Step); + return; + case StepOut: + case NotStepping: + break; + } + + if (m_pauseRequested) { // Serve debugging requests from the agent + m_pauseRequested = false; + pauseAndWait(PauseRequest); + } else if (m_haveBreakPoints) { + if (QV4::Function *f = getFunction()) { + const int lineNumber = engine()->current->lineNumber; + if (reallyHitTheBreakPoint(f->sourceFile(), lineNumber)) + pauseAndWait(BreakPointHit); + } + } +} + +void QV4Debugger::enteringFunction() +{ + if (m_runningJob) + return; + QMutexLocker locker(&m_lock); + + if (m_stepping == StepIn) { + m_currentContext.set(m_engine, *m_engine->currentContext); + } +} + +void QV4Debugger::leavingFunction(const QV4::ReturnedValue &retVal) +{ + if (m_runningJob) + return; + Q_UNUSED(retVal); // TODO + + QMutexLocker locker(&m_lock); + + if (m_stepping != NotStepping && m_currentContext.asManaged()->d() == m_engine->current) { + m_currentContext.set(m_engine, *m_engine->parentContext(m_engine->currentContext)); + m_stepping = StepOver; + m_returnedValue.set(m_engine, retVal); + } +} + +void QV4Debugger::aboutToThrow() +{ + if (!m_breakOnThrow) + return; + + if (m_runningJob) // do not re-enter when we're doing a job for the debugger. + return; + + QMutexLocker locker(&m_lock); + pauseAndWait(Throwing); +} + +QV4::Function *QV4Debugger::getFunction() const +{ + QV4::Scope scope(m_engine); + QV4::ExecutionContext *context = m_engine->currentContext; + QV4::ScopedFunctionObject function(scope, context->getFunctionObject()); + if (function) + return function->function(); + else + return context->d()->engine->globalCode; +} + +void QV4Debugger::runJobUnpaused() +{ + QMutexLocker locker(&m_lock); + if (m_runningJob) + m_runningJob->run(); + m_jobIsRunning.wakeAll(); +} + +void QV4Debugger::pauseAndWait(PauseReason reason) +{ + if (m_runningJob) + return; + + m_state = Paused; + emit debuggerPaused(this, reason); + + while (true) { + m_runningCondition.wait(&m_lock); + if (m_runningJob) { + m_runningJob->run(); + m_jobIsRunning.wakeAll(); + } else { + break; + } + } + + m_state = Running; +} + +bool QV4Debugger::reallyHitTheBreakPoint(const QString &filename, int linenr) +{ + QHash<BreakPoint, QString>::iterator it = m_breakPoints.find( + BreakPoint(filename.mid(filename.lastIndexOf('/') + 1), linenr)); + if (it == m_breakPoints.end()) + return false; + QString condition = it.value(); + if (condition.isEmpty()) + return true; + + Q_ASSERT(m_runningJob == 0); + EvalJob evilJob(m_engine, condition); + m_runningJob = &evilJob; + m_runningJob->run(); + m_runningJob = 0; + + return evilJob.resultAsBoolean(); +} + +void QV4Debugger::runInEngine(QV4DebugJob *job) +{ + QMutexLocker locker(&m_lock); + runInEngine_havingLock(job); +} + +void QV4Debugger::runInEngine_havingLock(QV4DebugJob *job) +{ + Q_ASSERT(job); + Q_ASSERT(m_runningJob == 0); + + m_runningJob = job; + if (state() == Paused) + m_runningCondition.wakeAll(); + else + QMetaObject::invokeMethod(this, "runJobUnpaused", Qt::QueuedConnection); + m_jobIsRunning.wait(&m_lock); + m_runningJob = 0; +} + +QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h new file mode 100644 index 0000000000..3a5b6080cb --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h @@ -0,0 +1,177 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QV4DEBUGGER_H +#define QV4DEBUGGER_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 "qv4datacollector.h" +#include <private/qv4debugging_p.h> +#include <private/qv4function_p.h> +#include <private/qv4context_p.h> +#include <private/qv4persistent_p.h> + +#include <QtCore/qmutex.h> +#include <QtCore/qwaitcondition.h> + +QT_BEGIN_NAMESPACE + +class QV4DebugJob; +class QV4DataCollector; +class QV4Debugger : public QV4::Debugging::Debugger +{ + Q_OBJECT +public: + struct BreakPoint { + BreakPoint(const QString &fileName, int line); + QString fileName; + int lineNumber; + }; + + enum State { + Running, + Paused + }; + + enum Speed { + FullThrottle = 0, + StepOut, + StepOver, + StepIn, + + NotStepping = FullThrottle + }; + + enum PauseReason { + PauseRequest, + BreakPointHit, + Throwing, + Step + }; + + QV4Debugger(QV4::ExecutionEngine *engine); + + QV4::ExecutionEngine *engine() const; + const QV4DataCollector *collector() const; + QV4DataCollector *collector(); + + void pause(); + void resume(Speed speed); + + State state() const; + + void addBreakPoint(const QString &fileName, int lineNumber, + const QString &condition = QString()); + void removeBreakPoint(const QString &fileName, int lineNumber); + + void setBreakOnThrow(bool onoff); + + void clearPauseRequest(); + + // used for testing + struct ExecutionState + { + QString fileName; + int lineNumber; + }; + ExecutionState currentExecutionState() const; + + QVector<QV4::StackFrame> stackTrace(int frameLimit = -1) const; + QVector<QV4::Heap::ExecutionContext::ContextType> getScopeTypes(int frame = 0) const; + + QV4::Function *getFunction() const; + void runInEngine(QV4DebugJob *job); + + // compile-time interface + void maybeBreakAtInstruction() Q_DECL_OVERRIDE; + + // execution hooks + void enteringFunction() Q_DECL_OVERRIDE; + void leavingFunction(const QV4::ReturnedValue &retVal) Q_DECL_OVERRIDE; + void aboutToThrow() Q_DECL_OVERRIDE; + + bool pauseAtNextOpportunity() const Q_DECL_OVERRIDE; + +signals: + void debuggerPaused(QV4Debugger *self, QV4Debugger::PauseReason reason); + +private slots: + void runJobUnpaused(); + +private: + // requires lock to be held + void pauseAndWait(PauseReason reason); + bool reallyHitTheBreakPoint(const QString &filename, int linenr); + void runInEngine_havingLock(QV4DebugJob *job); + + QV4::ExecutionEngine *m_engine; + QV4::PersistentValue m_currentContext; + QMutex m_lock; + QWaitCondition m_runningCondition; + State m_state; + Speed m_stepping; + bool m_pauseRequested; + bool m_haveBreakPoints; + bool m_breakOnThrow; + + QHash<BreakPoint, QString> m_breakPoints; + QV4::PersistentValue m_returnedValue; + + QV4DebugJob *m_gatherSources; + QV4DebugJob *m_runningJob; + QV4DataCollector m_collector; + QWaitCondition m_jobIsRunning; +}; + +QT_END_NAMESPACE + +Q_DECLARE_METATYPE(QV4Debugger::PauseReason) +Q_DECLARE_METATYPE(QV4Debugger*) + +#endif // QV4DEBUGGER_H diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp index e33595c629..a90d03b010 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -44,38 +50,34 @@ QV4DebuggerAgent::QV4DebuggerAgent(QV4DebugServiceImpl *debugService) : m_breakOnThrow(false), m_debugService(debugService) {} -QV4::Debugging::V4Debugger *QV4DebuggerAgent::firstDebugger() const +QV4Debugger *QV4DebuggerAgent::pausedDebugger() const { - // Currently only 1 single engine is supported, so: - if (m_debuggers.isEmpty()) - return 0; - else - return m_debuggers.first(); + foreach (QV4Debugger *debugger, m_debuggers) { + if (debugger->state() == QV4Debugger::Paused) + return debugger; + } + return 0; } bool QV4DebuggerAgent::isRunning() const { - // Currently only 1 single engine is supported, so: - if (QV4::Debugging::V4Debugger *debugger = firstDebugger()) - return debugger->state() == QV4::Debugging::V4Debugger::Running; - else - return false; + // "running" means none of the engines are paused. + return pausedDebugger() == 0; } -void QV4DebuggerAgent::debuggerPaused(QV4::Debugging::V4Debugger *debugger, - QV4::Debugging::PauseReason reason) +void QV4DebuggerAgent::debuggerPaused(QV4Debugger *debugger, QV4Debugger::PauseReason reason) { Q_UNUSED(reason); - m_debugService->clearHandles(debugger->engine()); + debugger->collector()->clear(); QJsonObject event, body, script; event.insert(QStringLiteral("type"), QStringLiteral("event")); switch (reason) { - case QV4::Debugging::Step: - case QV4::Debugging::PauseRequest: - case QV4::Debugging::BreakPoint: { + case QV4Debugger::Step: + case QV4Debugger::PauseRequest: + case QV4Debugger::BreakPointHit: { event.insert(QStringLiteral("event"), QStringLiteral("break")); QVector<QV4::StackFrame> frames = debugger->stackTrace(1); if (frames.isEmpty()) @@ -92,7 +94,7 @@ void QV4DebuggerAgent::debuggerPaused(QV4::Debugging::V4Debugger *debugger, body.insert(QStringLiteral("breakpoints"), breakPoints); script.insert(QStringLiteral("name"), topFrame.source); } break; - case QV4::Debugging::Throwing: + case QV4Debugger::Throwing: // TODO: complete this! event.insert(QStringLiteral("event"), QStringLiteral("exception")); break; @@ -105,28 +107,7 @@ void QV4DebuggerAgent::debuggerPaused(QV4::Debugging::V4Debugger *debugger, m_debugService->send(event); } -void QV4DebuggerAgent::sourcesCollected(QV4::Debugging::V4Debugger *debugger, - const QStringList &sources, int requestSequenceNr) -{ - QJsonArray body; - foreach (const QString &source, sources) { - QJsonObject src; - src[QLatin1String("name")] = source; - src[QLatin1String("scriptType")] = 4; - body.append(src); - } - - QJsonObject response; - response[QLatin1String("success")] = true; - response[QLatin1String("running")] = debugger->state() == QV4::Debugging::V4Debugger::Running; - response[QLatin1String("body")] = body; - response[QLatin1String("command")] = QStringLiteral("scripts"); - response[QLatin1String("request_seq")] = requestSequenceNr; - response[QLatin1String("type")] = QStringLiteral("response"); - m_debugService->send(response); -} - -void QV4DebuggerAgent::addDebugger(QV4::Debugging::V4Debugger *debugger) +void QV4DebuggerAgent::addDebugger(QV4Debugger *debugger) { Q_ASSERT(!m_debuggers.contains(debugger)); m_debuggers << debugger; @@ -137,57 +118,50 @@ void QV4DebuggerAgent::addDebugger(QV4::Debugging::V4Debugger *debugger) if (breakPoint.enabled) debugger->addBreakPoint(breakPoint.fileName, breakPoint.lineNr, breakPoint.condition); - connect(debugger, SIGNAL(destroyed(QObject*)), - this, SLOT(handleDebuggerDeleted(QObject*))); - connect(debugger, SIGNAL(sourcesCollected(QV4::Debugging::V4Debugger*,QStringList,int)), - this, SLOT(sourcesCollected(QV4::Debugging::V4Debugger*,QStringList,int)), - Qt::QueuedConnection); - connect(debugger, - SIGNAL(debuggerPaused(QV4::Debugging::V4Debugger*,QV4::Debugging::PauseReason)), - this, SLOT(debuggerPaused(QV4::Debugging::V4Debugger*,QV4::Debugging::PauseReason)), + connect(debugger, &QObject::destroyed, this, &QV4DebuggerAgent::handleDebuggerDeleted); + connect(debugger, &QV4Debugger::debuggerPaused, this, &QV4DebuggerAgent::debuggerPaused, Qt::QueuedConnection); } -void QV4DebuggerAgent::removeDebugger(QV4::Debugging::V4Debugger *debugger) +void QV4DebuggerAgent::removeDebugger(QV4Debugger *debugger) { m_debuggers.removeAll(debugger); - disconnect(debugger, SIGNAL(destroyed(QObject*)), - this, SLOT(handleDebuggerDeleted(QObject*))); - disconnect(debugger, SIGNAL(sourcesCollected(QV4::Debugging::V4Debugger*,QStringList,int)), - this, SLOT(sourcesCollected(QV4::Debugging::V4Debugger*,QStringList,int))); - disconnect(debugger, - SIGNAL(debuggerPaused(QV4::Debugging::V4Debugger*,QV4::Debugging::PauseReason)), - this, - SLOT(debuggerPaused(QV4::Debugging::V4Debugger*,QV4::Debugging::PauseReason))); + disconnect(debugger, &QObject::destroyed, this, &QV4DebuggerAgent::handleDebuggerDeleted); + disconnect(debugger, &QV4Debugger::debuggerPaused, this, &QV4DebuggerAgent::debuggerPaused); +} + +const QList<QV4Debugger *> &QV4DebuggerAgent::debuggers() +{ + return m_debuggers; } void QV4DebuggerAgent::handleDebuggerDeleted(QObject *debugger) { - m_debuggers.removeAll(static_cast<QV4::Debugging::V4Debugger *>(debugger)); + m_debuggers.removeAll(static_cast<QV4Debugger *>(debugger)); } -void QV4DebuggerAgent::pause(QV4::Debugging::V4Debugger *debugger) const +void QV4DebuggerAgent::pause(QV4Debugger *debugger) const { debugger->pause(); } void QV4DebuggerAgent::pauseAll() const { - foreach (QV4::Debugging::V4Debugger *debugger, m_debuggers) + foreach (QV4Debugger *debugger, m_debuggers) pause(debugger); } void QV4DebuggerAgent::resumeAll() const { - foreach (QV4::Debugging::V4Debugger *debugger, m_debuggers) - if (debugger->state() == QV4::Debugging::V4Debugger::Paused) - debugger->resume(QV4::Debugging::V4Debugger::FullThrottle); + foreach (QV4Debugger *debugger, m_debuggers) + if (debugger->state() == QV4Debugger::Paused) + debugger->resume(QV4Debugger::FullThrottle); } int QV4DebuggerAgent::addBreakPoint(const QString &fileName, int lineNumber, bool enabled, const QString &condition) { if (enabled) - foreach (QV4::Debugging::V4Debugger *debugger, m_debuggers) + foreach (QV4Debugger *debugger, m_debuggers) debugger->addBreakPoint(fileName, lineNumber, condition); int id = m_breakPoints.size(); @@ -204,15 +178,14 @@ void QV4DebuggerAgent::removeBreakPoint(int id) m_breakPoints.remove(id); if (breakPoint.enabled) - foreach (QV4::Debugging::V4Debugger *debugger, m_debuggers) + foreach (QV4Debugger *debugger, m_debuggers) debugger->removeBreakPoint(breakPoint.fileName, breakPoint.lineNr); } void QV4DebuggerAgent::removeAllBreakPoints() { - QList<int> ids = m_breakPoints.keys(); - foreach (int id, ids) - removeBreakPoint(id); + for (auto it = m_breakPoints.keyBegin(), end = m_breakPoints.keyEnd(); it != end; ++it) + removeBreakPoint(*it); } void QV4DebuggerAgent::enableBreakPoint(int id, bool onoff) @@ -222,7 +195,7 @@ void QV4DebuggerAgent::enableBreakPoint(int id, bool onoff) return; breakPoint.enabled = onoff; - foreach (QV4::Debugging::V4Debugger *debugger, m_debuggers) { + foreach (QV4Debugger *debugger, m_debuggers) { if (onoff) debugger->addBreakPoint(breakPoint.fileName, breakPoint.lineNr, breakPoint.condition); else @@ -245,9 +218,15 @@ void QV4DebuggerAgent::setBreakOnThrow(bool onoff) { if (onoff != m_breakOnThrow) { m_breakOnThrow = onoff; - foreach (QV4::Debugging::V4Debugger *debugger, m_debuggers) + foreach (QV4Debugger *debugger, m_debuggers) debugger->setBreakOnThrow(onoff); } } +void QV4DebuggerAgent::clearAllPauseRequests() +{ + foreach (QV4Debugger *debugger, m_debuggers) + debugger->clearPauseRequest(); +} + QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h index eafb408e7a..1c7eb50ac7 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -34,7 +40,7 @@ #ifndef QV4DEBUGGERAGENT_H #define QV4DEBUGGERAGENT_H -#include <private/qv4debugging_p.h> +#include "qv4debugger.h" QT_BEGIN_NAMESPACE @@ -46,13 +52,14 @@ class QV4DebuggerAgent : public QObject public: QV4DebuggerAgent(QV4DebugServiceImpl *m_debugService); - QV4::Debugging::V4Debugger *firstDebugger() const; + QV4Debugger *pausedDebugger() const; bool isRunning() const; - void addDebugger(QV4::Debugging::V4Debugger *debugger); - void removeDebugger(QV4::Debugging::V4Debugger *debugger); + void addDebugger(QV4Debugger *debugger); + void removeDebugger(QV4Debugger *debugger); + const QList<QV4Debugger *> &debuggers(); - void pause(QV4::Debugging::V4Debugger *debugger) const; + void pause(QV4Debugger *debugger) const; void pauseAll() const; void resumeAll() const; int addBreakPoint(const QString &fileName, int lineNumber, bool enabled = true, const QString &condition = QString()); @@ -63,15 +70,14 @@ public: bool breakOnThrow() const { return m_breakOnThrow; } void setBreakOnThrow(bool onoff); + void clearAllPauseRequests(); public slots: - void debuggerPaused(QV4::Debugging::V4Debugger *debugger, QV4::Debugging::PauseReason reason); - void sourcesCollected(QV4::Debugging::V4Debugger *debugger, const QStringList &sources, - int requestSequenceNr); + void debuggerPaused(QV4Debugger *debugger, QV4Debugger::PauseReason reason); void handleDebuggerDeleted(QObject *debugger); private: - QList<QV4::Debugging::V4Debugger *> m_debuggers; + QList<QV4Debugger *> m_debuggers; struct BreakPoint { QString fileName; diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp new file mode 100644 index 0000000000..a2d2fff72b --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp @@ -0,0 +1,287 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qv4debugjob.h" + +#include <private/qv4script_p.h> +#include <private/qqmlcontext_p.h> +#include <private/qv4qobjectwrapper_p.h> + +#include <QtQml/qqmlengine.h> + +QT_BEGIN_NAMESPACE + +QV4DebugJob::~QV4DebugJob() +{ +} + +JavaScriptJob::JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr, + const QString &script) : + engine(engine), frameNr(frameNr), script(script), resultIsException(false) +{} + +void JavaScriptJob::run() +{ + QV4::Scope scope(engine); + + QV4::ExecutionContextSaver saver(scope); + + QV4::ExecutionContext *ctx = engine->currentContext; + QObject scopeObject; + if (frameNr < 0) { // Use QML context if available + QQmlEngine *qmlEngine = engine->qmlEngine(); + if (qmlEngine) { + QQmlContext *qmlRootContext = qmlEngine->rootContext(); + QQmlContextPrivate *ctxtPriv = QQmlContextPrivate::get(qmlRootContext); + + QV4::ScopedObject withContext(scope, engine->newObject()); + for (int ii = 0; ii < ctxtPriv->instances.count(); ++ii) { + QObject *object = ctxtPriv->instances.at(ii); + if (QQmlContext *context = qmlContext(object)) { + if (QQmlContextData *cdata = QQmlContextData::get(context)) { + QV4::ScopedValue v(scope, QV4::QObjectWrapper::wrap(engine, object)); + withContext->put(engine, cdata->findObjectId(object), v); + } + } + } + if (!engine->qmlContext()) { + engine->pushContext(ctx->newQmlContext(QQmlContextData::get(qmlRootContext), + &scopeObject)); + ctx = engine->currentContext; + } + engine->pushContext(ctx->newWithContext(withContext->toObject(engine))); + ctx = engine->currentContext; + } + } else { + if (frameNr > 0) { + for (int i = 0; i < frameNr; ++i) { + ctx = engine->parentContext(ctx); + } + engine->pushContext(ctx); + } + } + + QV4::Script script(ctx, this->script); + script.strictMode = ctx->d()->strictMode; + // In order for property lookups in QML to work, we need to disable fast v4 lookups. That + // is a side-effect of inheritContext. + script.inheritContext = true; + script.parse(); + QV4::ScopedValue result(scope); + if (!scope.engine->hasException) + result = script.run(); + if (scope.engine->hasException) { + result = scope.engine->catchException(); + resultIsException = true; + } + handleResult(result); +} + +bool JavaScriptJob::hasExeption() const +{ + return resultIsException; +} + +BacktraceJob::BacktraceJob(QV4DataCollector *collector, int fromFrame, int toFrame) : + CollectJob(collector), fromFrame(fromFrame), toFrame(toFrame) +{ +} + +void BacktraceJob::run() +{ + QJsonArray frameArray; + QVector<QV4::StackFrame> frames = collector->engine()->stackTrace(toFrame); + for (int i = fromFrame; i < toFrame && i < frames.size(); ++i) + frameArray.push_back(collector->buildFrame(frames[i], i)); + if (frameArray.isEmpty()) { + result.insert(QStringLiteral("totalFrames"), 0); + } else { + result.insert(QStringLiteral("fromFrame"), fromFrame); + result.insert(QStringLiteral("toFrame"), fromFrame + frameArray.size()); + result.insert(QStringLiteral("frames"), frameArray); + } + collectedRefs = collector->flushCollectedRefs(); +} + +FrameJob::FrameJob(QV4DataCollector *collector, int frameNr) : + CollectJob(collector), frameNr(frameNr), success(false) +{ +} + +void FrameJob::run() +{ + QVector<QV4::StackFrame> frames = collector->engine()->stackTrace(frameNr + 1); + if (frameNr >= frames.length()) { + success = false; + } else { + result = collector->buildFrame(frames[frameNr], frameNr); + collectedRefs = collector->flushCollectedRefs(); + success = true; + } +} + +bool FrameJob::wasSuccessful() const +{ + return success; +} + +ScopeJob::ScopeJob(QV4DataCollector *collector, int frameNr, int scopeNr) : + CollectJob(collector), frameNr(frameNr), scopeNr(scopeNr), success(false) +{ +} + +void ScopeJob::run() +{ + QJsonObject object; + success = collector->collectScope(&object, frameNr, scopeNr); + + if (success) { + QVector<QV4::Heap::ExecutionContext::ContextType> scopeTypes = + collector->getScopeTypes(frameNr); + result[QLatin1String("type")] = QV4DataCollector::encodeScopeType(scopeTypes[scopeNr]); + } else { + result[QLatin1String("type")] = -1; + } + result[QLatin1String("index")] = scopeNr; + result[QLatin1String("frameIndex")] = frameNr; + result[QLatin1String("object")] = object; + collectedRefs = collector->flushCollectedRefs(); +} + +bool ScopeJob::wasSuccessful() const +{ + return success; +} + +ValueLookupJob::ValueLookupJob(const QJsonArray &handles, QV4DataCollector *collector) : + CollectJob(collector), handles(handles) {} + +void ValueLookupJob::run() +{ + // Open a QML context if we don't have one, yet. We might run into QML objects when looking up + // refs and that will crash without a valid QML context. Mind that engine->qmlContext() is only + // set if the engine is currently executing QML code. + QScopedPointer<QObject> scopeObject; + QV4::ExecutionEngine *engine = collector->engine(); + if (engine->qmlEngine() && !engine->qmlContext()) { + scopeObject.reset(new QObject); + engine->pushContext(engine->currentContext->newQmlContext( + QQmlContextData::get(engine->qmlEngine()->rootContext()), + scopeObject.data())); + } + foreach (const QJsonValue &handle, handles) { + QV4DataCollector::Ref ref = handle.toInt(); + if (!collector->isValidRef(ref)) { + exception = QString::fromLatin1("Invalid Ref: %1").arg(ref); + break; + } + result[QString::number(ref)] = collector->lookupRef(ref); + } + collectedRefs = collector->flushCollectedRefs(); + if (scopeObject) + engine->popContext(); +} + +const QString &ValueLookupJob::exceptionMessage() const +{ + return exception; +} + +ExpressionEvalJob::ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, + const QString &expression, QV4DataCollector *collector) : + JavaScriptJob(engine, frameNr, expression), collector(collector) +{ +} + +void ExpressionEvalJob::handleResult(QV4::ScopedValue &value) +{ + if (hasExeption()) + exception = value->toQStringNoThrow(); + result = collector->lookupRef(collector->collect(value)); + collectedRefs = collector->flushCollectedRefs(); +} + +const QString &ExpressionEvalJob::exceptionMessage() const +{ + return exception; +} + +const QJsonObject &ExpressionEvalJob::returnValue() const +{ + return result; +} + +const QJsonArray &ExpressionEvalJob::refs() const +{ + return collectedRefs; +} + +GatherSourcesJob::GatherSourcesJob(QV4::ExecutionEngine *engine) + : engine(engine) +{} + +void GatherSourcesJob::run() +{ + foreach (QV4::CompiledData::CompilationUnit *unit, engine->compilationUnits) { + QString fileName = unit->fileName(); + if (!fileName.isEmpty()) + sources.append(fileName); + } +} + +const QStringList &GatherSourcesJob::result() const +{ + return sources; +} + +EvalJob::EvalJob(QV4::ExecutionEngine *engine, const QString &script) : + JavaScriptJob(engine, /*frameNr*/-1, script), result(false) +{} + +void EvalJob::handleResult(QV4::ScopedValue &result) +{ + this->result = result->toBoolean(); +} + +bool EvalJob::resultAsBoolean() const +{ + return result; +} + +QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h new file mode 100644 index 0000000000..721f42b7c2 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h @@ -0,0 +1,171 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QV4DEBUGJOB_H +#define QV4DEBUGJOB_H + +#include "qv4datacollector.h" +#include <private/qv4engine_p.h> + +#include <QtCore/qjsonarray.h> +#include <QtCore/qjsonobject.h> + +QT_BEGIN_NAMESPACE + +class QV4DataCollector; +class QV4DebugJob +{ +public: + virtual ~QV4DebugJob(); + virtual void run() = 0; +}; + +class JavaScriptJob : public QV4DebugJob +{ + QV4::ExecutionEngine *engine; + int frameNr; + const QString &script; + bool resultIsException; + +public: + JavaScriptJob(QV4::ExecutionEngine *engine, int frameNr, const QString &script); + void run(); + bool hasExeption() const; + +protected: + virtual void handleResult(QV4::ScopedValue &result) = 0; +}; + +class CollectJob : public QV4DebugJob +{ +protected: + QV4DataCollector *collector; + QJsonObject result; + QJsonArray collectedRefs; +public: + CollectJob(QV4DataCollector *collector) : collector(collector) {} + const QJsonObject &returnValue() const { return result; } + const QJsonArray &refs() const { return collectedRefs; } +}; + +class BacktraceJob: public CollectJob +{ + int fromFrame; + int toFrame; +public: + BacktraceJob(QV4DataCollector *collector, int fromFrame, int toFrame); + void run(); +}; + +class FrameJob: public CollectJob +{ + int frameNr; + bool success; + +public: + FrameJob(QV4DataCollector *collector, int frameNr); + void run(); + bool wasSuccessful() const; +}; + +class ScopeJob: public CollectJob +{ + int frameNr; + int scopeNr; + bool success; + +public: + ScopeJob(QV4DataCollector *collector, int frameNr, int scopeNr); + void run(); + bool wasSuccessful() const; +}; + +class ValueLookupJob: public CollectJob +{ + const QJsonArray handles; + QString exception; + +public: + ValueLookupJob(const QJsonArray &handles, QV4DataCollector *collector); + void run(); + const QString &exceptionMessage() const; +}; + +class ExpressionEvalJob: public JavaScriptJob +{ + QV4DataCollector *collector; + QString exception; + QJsonObject result; + QJsonArray collectedRefs; + +public: + ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, const QString &expression, + QV4DataCollector *collector); + virtual void handleResult(QV4::ScopedValue &value); + const QString &exceptionMessage() const; + const QJsonObject &returnValue() const; + const QJsonArray &refs() const; +}; + +class GatherSourcesJob: public QV4DebugJob +{ + QV4::ExecutionEngine *engine; + QStringList sources; + +public: + GatherSourcesJob(QV4::ExecutionEngine *engine); + void run(); + const QStringList &result() const; +}; + +class EvalJob: public JavaScriptJob +{ + bool result; + +public: + EvalJob(QV4::ExecutionEngine *engine, const QString &script); + + virtual void handleResult(QV4::ScopedValue &result); + bool resultAsBoolean() const; +}; + +QT_END_NAMESPACE + +#endif // QV4DEBUGJOB_H + diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp index 7a9d4a66a4..5ee9e5e9e9 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp @@ -1,43 +1,51 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qv4debugservice.h" +#include "qv4debugjob.h" #include "qqmlengine.h" +#include "qqmldebugpacket.h" + #include <private/qv4engine_p.h> #include <private/qv4isel_moth_p.h> #include <private/qv4function_p.h> #include <private/qqmldebugconnector_p.h> - #include <private/qv8engine_p.h> #include <QtCore/QJsonArray> @@ -63,7 +71,6 @@ QT_BEGIN_NAMESPACE class V8CommandHandler; class UnknownV8CommandHandler; -int QV4DebugServiceImpl::debuggerIndex = 0; int QV4DebugServiceImpl::sequence = 0; class V8CommandHandler @@ -104,7 +111,7 @@ protected: void addCommand() { response.insert(QStringLiteral("command"), cmd); } void addRequestSequence() { response.insert(QStringLiteral("request_seq"), seq); } void addSuccess(bool success) { response.insert(QStringLiteral("success"), success); } - void addBody(const QJsonObject &body) + void addBody(const QJsonValue &body) { response.insert(QStringLiteral("body"), body); } @@ -169,6 +176,7 @@ public: QJsonObject body; body.insert(QStringLiteral("V8Version"), QLatin1String("this is not V8, this is V4 in Qt " QT_VERSION_STR)); + body.insert(QStringLiteral("UnpausedEvaluate"), true); addBody(body); } }; @@ -271,8 +279,14 @@ public: int toFrame = arguments.value(QStringLiteral("toFrame")).toInt(fromFrame + 10); // no idea what the bottom property is for, so we'll ignore it. - BacktraceJob job(debugService->collector(), fromFrame, toFrame); - debugService->debuggerAgent.firstDebugger()->runInEngine(&job); + QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger(); + if (!debugger) { + createErrorResponse(QStringLiteral("Debugger has to be paused to retrieve backtraces.")); + return; + } + + BacktraceJob job(debugger->collector(), fromFrame, toFrame); + debugger->runInEngine(&job); // response: addCommand(); @@ -296,13 +310,19 @@ public: const int frameNr = arguments.value(QStringLiteral("number")).toInt( debugService->selectedFrame()); + QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger(); + if (!debugger) { + createErrorResponse(QStringLiteral("Debugger has to be paused to retrieve frames.")); + return; + } + if (frameNr < 0) { createErrorResponse(QStringLiteral("frame command has invalid frame number")); return; } - FrameJob job(debugService->collector(), frameNr); - debugService->debuggerAgent.firstDebugger()->runInEngine(&job); + FrameJob job(debugger->collector(), frameNr); + debugger->runInEngine(&job); if (!job.wasSuccessful()) { createErrorResponse(QStringLiteral("frame retrieval failed")); return; @@ -333,6 +353,12 @@ public: debugService->selectedFrame()); const int scopeNr = arguments.value(QStringLiteral("number")).toInt(0); + QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger(); + if (!debugger) { + createErrorResponse(QStringLiteral("Debugger has to be paused to retrieve scope.")); + return; + } + if (frameNr < 0) { createErrorResponse(QStringLiteral("scope command has invalid frame number")); return; @@ -342,8 +368,8 @@ public: return; } - ScopeJob job(debugService->collector(), frameNr, scopeNr); - debugService->debuggerAgent.firstDebugger()->runInEngine(&job); + ScopeJob job(debugger->collector(), frameNr, scopeNr); + debugger->runInEngine(&job); if (!job.wasSuccessful()) { createErrorResponse(QStringLiteral("scope retrieval failed")); return; @@ -370,8 +396,21 @@ public: QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject(); QJsonArray handles = arguments.value(QStringLiteral("handles")).toArray(); - ValueLookupJob job(handles, debugService->collector()); - debugService->debuggerAgent.firstDebugger()->runInEngine(&job); + QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger(); + if (!debugger) { + const QList<QV4Debugger *> &debuggers = debugService->debuggerAgent.debuggers(); + if (debuggers.count() > 1) { + createErrorResponse(QStringLiteral("Cannot lookup values if multiple debuggers are running and none is paused")); + return; + } else if (debuggers.count() == 0) { + createErrorResponse(QStringLiteral("No debuggers available to lookup values")); + return; + } + debugger = debuggers.first(); + } + + ValueLookupJob job(handles, debugger->collector()); + debugger->runInEngine(&job); if (!job.exceptionMessage().isEmpty()) { createErrorResponse(job.exceptionMessage()); } else { @@ -396,10 +435,15 @@ public: // decypher the payload: QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject(); - QV4::Debugging::V4Debugger *debugger = debugService->debuggerAgent.firstDebugger(); + QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger(); + if (!debugger) { + createErrorResponse(QStringLiteral("Debugger has to be paused in order to continue.")); + return; + } + debugService->debuggerAgent.clearAllPauseRequests(); if (arguments.empty()) { - debugger->resume(QV4::Debugging::V4Debugger::FullThrottle); + debugger->resume(QV4Debugger::FullThrottle); } else { QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject(); QString stepAction = arguments.value(QStringLiteral("stepaction")).toString(); @@ -408,11 +452,11 @@ public: qWarning() << "Step count other than 1 is not supported."; if (stepAction == QStringLiteral("in")) { - debugger->resume(QV4::Debugging::V4Debugger::StepIn); + debugger->resume(QV4Debugger::StepIn); } else if (stepAction == QStringLiteral("out")) { - debugger->resume(QV4::Debugging::V4Debugger::StepOut); + debugger->resume(QV4Debugger::StepOut); } else if (stepAction == QStringLiteral("next")) { - debugger->resume(QV4::Debugging::V4Debugger::StepOver); + debugger->resume(QV4Debugger::StepOver); } else { createErrorResponse(QStringLiteral("continue command has invalid stepaction")); return; @@ -504,11 +548,28 @@ public: } // do it: - QV4::Debugging::V4Debugger *debugger = debugService->debuggerAgent.firstDebugger(); - GatherSourcesJob job(debugger->engine(), requestSequenceNr()); + QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger(); + if (!debugger) { + createErrorResponse(QStringLiteral("Debugger has to be paused to retrieve scripts.")); + return; + } + + GatherSourcesJob job(debugger->engine()); debugger->runInEngine(&job); - // response will be send by + QJsonArray body; + foreach (const QString &source, job.result()) { + QJsonObject src; + src[QLatin1String("name")] = source; + src[QLatin1String("scriptType")] = 4; + body.append(src); + } + + addSuccess(true); + addRunning(); + addBody(body); + addCommand(); + addRequestSequence(); } }; @@ -547,27 +608,36 @@ public: virtual void handleRequest() { - QV4::Debugging::V4Debugger *debugger = debugService->debuggerAgent.firstDebugger(); - if (debugger->state() == QV4::Debugging::V4Debugger::Paused) { - QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject(); - QString expression = arguments.value(QStringLiteral("expression")).toString(); - const int frame = arguments.value(QStringLiteral("frame")).toInt(0); - - QV4DataCollector *collector = debugService->collector(); - ExpressionEvalJob job(debugger->engine(), frame, expression, collector); - debugger->runInEngine(&job); - if (job.hasExeption()) { - createErrorResponse(job.exceptionMessage()); - } else { - addCommand(); - addRequestSequence(); - addSuccess(true); - addRunning(); - addBody(job.returnValue()); - addRefs(job.refs()); + QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject(); + QString expression = arguments.value(QStringLiteral("expression")).toString(); + int frame = -1; + + QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger(); + if (!debugger) { + const QList<QV4Debugger *> &debuggers = debugService->debuggerAgent.debuggers(); + if (debuggers.count() > 1) { + createErrorResponse(QStringLiteral("Cannot evaluate expressions if multiple debuggers are running and none is paused")); + return; + } else if (debuggers.count() == 0) { + createErrorResponse(QStringLiteral("No debuggers available to evaluate expressions")); + return; } + debugger = debuggers.first(); } else { - createErrorResponse(QStringLiteral("Debugger has to be paused for evaluate to work.")); + frame = arguments.value(QStringLiteral("frame")).toInt(0); + } + + ExpressionEvalJob job(debugger->engine(), frame, expression, debugger->collector()); + debugger->runInEngine(&job); + if (job.hasExeption()) { + createErrorResponse(job.exceptionMessage()); + } else { + addCommand(); + addRequestSequence(); + addSuccess(true); + addRunning(); + addBody(job.returnValue()); + addRefs(job.refs()); } } }; @@ -589,7 +659,7 @@ V8CommandHandler *QV4DebugServiceImpl::v8CommandHandler(const QString &command) QV4DebugServiceImpl::QV4DebugServiceImpl(QObject *parent) : QQmlConfigurableDebugService<QV4DebugService>(1, parent), - debuggerAgent(this), version(1), theSelectedFrame(0), + debuggerAgent(this), theSelectedFrame(0), unknownV8CommandHandler(new UnknownV8CommandHandler) { addHandler(new V8VersionRequest); @@ -611,7 +681,7 @@ QV4DebugServiceImpl::~QV4DebugServiceImpl() qDeleteAll(handlers); } -void QV4DebugServiceImpl::engineAdded(QQmlEngine *engine) +void QV4DebugServiceImpl::engineAdded(QJSEngine *engine) { QMutexLocker lock(&m_configMutex); if (engine) { @@ -619,10 +689,9 @@ void QV4DebugServiceImpl::engineAdded(QQmlEngine *engine) if (QQmlDebugConnector *server = QQmlDebugConnector::instance()) { if (ee) { ee->iselFactory.reset(new QV4::Moth::ISelFactory); - QV4::Debugging::V4Debugger *debugger = new QV4::Debugging::V4Debugger(ee); + QV4Debugger *debugger = new QV4Debugger(ee); if (state() == Enabled) ee->setDebugger(debugger); - debuggerMap.insert(debuggerIndex++, debugger); debuggerAgent.addDebugger(debugger); debuggerAgent.moveToThread(server->thread()); } @@ -631,25 +700,15 @@ void QV4DebugServiceImpl::engineAdded(QQmlEngine *engine) QQmlConfigurableDebugService<QV4DebugService>::engineAdded(engine); } -void QV4DebugServiceImpl::engineAboutToBeRemoved(QQmlEngine *engine) +void QV4DebugServiceImpl::engineAboutToBeRemoved(QJSEngine *engine) { QMutexLocker lock(&m_configMutex); if (engine){ const QV4::ExecutionEngine *ee = QV8Engine::getV4(engine->handle()); if (ee) { - QV4::Debugging::V4Debugger *debugger - = qobject_cast<QV4::Debugging::V4Debugger *>(ee->debugger); - if (debugger) { - typedef QMap<int, QV4::Debugging::V4Debugger *>::const_iterator DebuggerMapIterator; - const DebuggerMapIterator end = debuggerMap.constEnd(); - for (DebuggerMapIterator i = debuggerMap.constBegin(); i != end; ++i) { - if (i.value() == debugger) { - debuggerMap.remove(i.key()); - break; - } - } + QV4Debugger *debugger = qobject_cast<QV4Debugger *>(ee->debugger); + if (debugger) debuggerAgent.removeDebugger(debugger); - } } } QQmlConfigurableDebugService<QV4DebugService>::engineAboutToBeRemoved(engine); @@ -659,12 +718,10 @@ void QV4DebugServiceImpl::stateAboutToBeChanged(State state) { QMutexLocker lock(&m_configMutex); if (state == Enabled) { - typedef QMap<int, QV4::Debugging::V4Debugger *>::const_iterator DebuggerMapIterator; - const DebuggerMapIterator end = debuggerMap.constEnd(); - for (DebuggerMapIterator i = debuggerMap.constBegin(); i != end; ++i) { - QV4::ExecutionEngine *ee = i.value()->engine(); + foreach (QV4Debugger *debugger, debuggerAgent.debuggers()) { + QV4::ExecutionEngine *ee = debugger->engine(); if (!ee->debugger) - ee->setDebugger(i.value()); + ee->setDebugger(debugger); } } QQmlConfigurableDebugService<QV4DebugService>::stateAboutToBeChanged(state); @@ -692,7 +749,7 @@ void QV4DebugServiceImpl::messageReceived(const QByteArray &message) { QMutexLocker lock(&m_configMutex); - QQmlDebugStream ms(message); + QQmlDebugPacket ms(message); QByteArray header; ms >> header; @@ -733,11 +790,10 @@ void QV4DebugServiceImpl::messageReceived(const QByteArray &message) void QV4DebugServiceImpl::sendSomethingToSomebody(const char *type, int magicNumber) { - QByteArray response; - QQmlDebugStream rs(&response, QIODevice::WriteOnly); + QQmlDebugPacket rs; rs << QByteArray(type) - << QByteArray::number(version) << QByteArray::number(magicNumber); - emit messageToClient(name(), packMessage(type, response)); + << QByteArray::number(int(version())) << QByteArray::number(magicNumber); + emit messageToClient(name(), packMessage(type, rs.data())); } void QV4DebugServiceImpl::handleV8Request(const QByteArray &payload) @@ -757,11 +813,10 @@ void QV4DebugServiceImpl::handleV8Request(const QByteArray &payload) QByteArray QV4DebugServiceImpl::packMessage(const QByteArray &command, const QByteArray &message) { - QByteArray reply; - QQmlDebugStream rs(&reply, QIODevice::WriteOnly); + QQmlDebugPacket rs; static const QByteArray cmd("V8DEBUG"); rs << cmd << command << message; - return reply; + return rs.data(); } void QV4DebugServiceImpl::send(QJsonObject v8Payload) @@ -780,16 +835,6 @@ void QV4DebugServiceImpl::send(QJsonObject v8Payload) emit messageToClient(name(), packMessage("v8message", responseData)); } -void QV4DebugServiceImpl::clearHandles(QV4::ExecutionEngine *engine) -{ - theCollector.reset(new QV4DataCollector(engine)); -} - -QV4DataCollector *QV4DebugServiceImpl::collector() const -{ - return theCollector.data(); -} - void QV4DebugServiceImpl::selectFrame(int frameNr) { theSelectedFrame = frameNr; diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h index fafe7d90bf..69e32189b8 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -57,7 +63,6 @@ QT_BEGIN_NAMESPACE namespace QV4 { struct ExecutionEngine; } -class QQmlEngine; class VariableCollector; class V8CommandHandler; class UnknownV8CommandHandler; @@ -68,26 +73,23 @@ class QV4DebugServiceImpl : public QQmlConfigurableDebugService<QV4DebugService> Q_OBJECT public: explicit QV4DebugServiceImpl(QObject *parent = 0); - ~QV4DebugServiceImpl(); + ~QV4DebugServiceImpl() Q_DECL_OVERRIDE; - void engineAdded(QQmlEngine *engine); - void engineAboutToBeRemoved(QQmlEngine *engine); + void engineAdded(QJSEngine *engine) Q_DECL_OVERRIDE; + void engineAboutToBeRemoved(QJSEngine *engine) Q_DECL_OVERRIDE; - void stateAboutToBeChanged(State state); + void stateAboutToBeChanged(State state) Q_DECL_OVERRIDE; - void signalEmitted(const QString &signal); + void signalEmitted(const QString &signal) Q_DECL_OVERRIDE; void send(QJsonObject v8Payload); int selectedFrame() const; void selectFrame(int frameNr); - void clearHandles(QV4::ExecutionEngine *engine); - - QV4DataCollector *collector() const; QV4DebuggerAgent debuggerAgent; protected: - void messageReceived(const QByteArray &); + void messageReceived(const QByteArray &) Q_DECL_OVERRIDE; void sendSomethingToSomebody(const char *type, int magicNumber = 1); private: @@ -100,12 +102,7 @@ private: V8CommandHandler *v8CommandHandler(const QString &command) const; QStringList breakOnSignals; - QMap<int, QV4::Debugging::V4Debugger *> debuggerMap; - static int debuggerIndex; static int sequence; - const int version; - - QScopedPointer<QV4DataCollector> theCollector; int theSelectedFrame; void addHandler(V8CommandHandler* handler); diff --git a/src/plugins/qmltooling/qmldbg_inspector/abstracttool.cpp b/src/plugins/qmltooling/qmldbg_inspector/abstracttool.cpp deleted file mode 100644 index 3e059bed13..0000000000 --- a/src/plugins/qmltooling/qmldbg_inspector/abstracttool.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "abstracttool.h" - -#include "abstractviewinspector.h" - -QT_BEGIN_NAMESPACE - -namespace QmlJSDebugger { - -AbstractTool::AbstractTool(AbstractViewInspector *inspector) : - QObject(inspector), - m_inspector(inspector) -{ -} - -} // namespace QmlJSDebugger - -QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_inspector/abstracttool.h b/src/plugins/qmltooling/qmldbg_inspector/abstracttool.h deleted file mode 100644 index c796925866..0000000000 --- a/src/plugins/qmltooling/qmldbg_inspector/abstracttool.h +++ /dev/null @@ -1,85 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef ABSTRACTTOOL_H -#define ABSTRACTTOOL_H - -#include <QtCore/QObject> - -QT_BEGIN_NAMESPACE -class QMouseEvent; -class QKeyEvent; -class QWheelEvent; -class QTouchEvent; - -namespace QmlJSDebugger { - -class AbstractViewInspector; - -class AbstractTool : public QObject -{ - Q_OBJECT - -public: - explicit AbstractTool(AbstractViewInspector *inspector); - - AbstractViewInspector *inspector() const { return m_inspector; } - - virtual void enable(bool enable) = 0; - - virtual void leaveEvent(QEvent *event) = 0; - - virtual void mousePressEvent(QMouseEvent *event) = 0; - virtual void mouseMoveEvent(QMouseEvent *event) = 0; - virtual void mouseReleaseEvent(QMouseEvent *event) = 0; - virtual void mouseDoubleClickEvent(QMouseEvent *event) = 0; - - virtual void hoverMoveEvent(QMouseEvent *event) = 0; -#ifndef QT_NO_WHEELEVENT - virtual void wheelEvent(QWheelEvent *event) = 0; -#endif - - virtual void keyPressEvent(QKeyEvent *event) = 0; - virtual void keyReleaseEvent(QKeyEvent *keyEvent) = 0; - - virtual void touchEvent(QTouchEvent *) {} - -private: - AbstractViewInspector *m_inspector; -}; - -} // namespace QmlJSDebugger - -QT_END_NAMESPACE - -#endif // ABSTRACTTOOL_H diff --git a/src/plugins/qmltooling/qmldbg_inspector/abstractviewinspector.cpp b/src/plugins/qmltooling/qmldbg_inspector/abstractviewinspector.cpp deleted file mode 100644 index fa6dca7aca..0000000000 --- a/src/plugins/qmltooling/qmldbg_inspector/abstractviewinspector.cpp +++ /dev/null @@ -1,419 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "abstractviewinspector.h" -#include "abstracttool.h" - -#include <QtCore/QDebug> -#include <QtQml/QQmlEngine> -#include <QtQml/QQmlComponent> -#include <QtCore/private/qabstractanimation_p.h> -#include <QtQml/private/qqmldebugconnector_p.h> -#include <QtQml/private/qqmlcontext_p.h> - -#include <QtGui/QMouseEvent> -#include <QtGui/QTouchEvent> - -//INSPECTOR SERVICE PROTOCOL -// <HEADER><COMMAND><DATA> -// <HEADER> : <type{request, response, event}><requestId/eventId>[<response_success_bool>] -// <COMMAND> : {"enable", "disable", "select", "reload", "setAnimationSpeed", -// "showAppOnTop", "createObject", "destroyObject", "moveObject", -// "clearCache"} -// <DATA> : select: <debugIds_int_list> -// reload: <hash<changed_filename_string, filecontents_bytearray>> -// setAnimationSpeed: <speed_real> -// showAppOnTop: <set_bool> -// createObject: <qml_string><parentId_int><imports_string_list><filename_string> -// destroyObject: <debugId_int> -// moveObject: <debugId_int><newParentId_int> -// clearCache: void -// Response for "destroyObject" carries the <debugId_int> of the destroyed object. - -QT_BEGIN_NAMESPACE - -const char REQUEST[] = "request"; -const char RESPONSE[] = "response"; -const char EVENT[] = "event"; -const char ENABLE[] = "enable"; -const char DISABLE[] = "disable"; -const char SELECT[] = "select"; -const char RELOAD[] = "reload"; -const char SET_ANIMATION_SPEED[] = "setAnimationSpeed"; -const char SHOW_APP_ON_TOP[] = "showAppOnTop"; -const char CREATE_OBJECT[] = "createObject"; -const char DESTROY_OBJECT[] = "destroyObject"; -const char MOVE_OBJECT[] = "moveObject"; -const char CLEAR_CACHE[] = "clearCache"; - -namespace QmlJSDebugger { - - -AbstractViewInspector::AbstractViewInspector(QQmlDebugService *service, QObject *parent) : - QObject(parent), - m_enabled(false), - m_debugService(service), - m_eventId(0), - m_reloadEventId(-1) -{ -} - -void AbstractViewInspector::createQmlObject(const QString &qml, QObject *parent, - const QStringList &importList, - const QString &filename) -{ - if (!parent) - return; - - QString imports; - foreach (const QString &s, importList) { - imports += s; - imports += QLatin1Char('\n'); - } - - QQmlContext *parentContext = declarativeEngine()->contextForObject(parent); - QQmlComponent component(declarativeEngine()); - QByteArray constructedQml = QString(imports + qml).toLatin1(); - - component.setData(constructedQml, QUrl::fromLocalFile(filename)); - QObject *newObject = component.create(parentContext); - if (newObject) - reparentQmlObject(newObject, parent); -} - -void AbstractViewInspector::clearComponentCache() -{ - declarativeEngine()->clearComponentCache(); -} - -void AbstractViewInspector::setEnabled(bool value) -{ - if (m_enabled == value) - return; - - m_enabled = value; - foreach (AbstractTool *tool, m_tools) - tool->enable(m_enabled); -} - -void AbstractViewInspector::setAnimationSpeed(qreal slowDownFactor) -{ - QUnifiedTimer::instance()->setSlowModeEnabled(slowDownFactor != 1.0); - QUnifiedTimer::instance()->setSlowdownFactor(slowDownFactor); -} - -bool AbstractViewInspector::eventFilter(QObject *obj, QEvent *event) -{ - if (!enabled()) - return QObject::eventFilter(obj, event); - - switch (event->type()) { - case QEvent::Leave: - if (leaveEvent(event)) - return true; - break; - case QEvent::MouseButtonPress: - if (mousePressEvent(static_cast<QMouseEvent*>(event))) - return true; - break; - case QEvent::MouseMove: - if (mouseMoveEvent(static_cast<QMouseEvent*>(event))) - return true; - break; - case QEvent::MouseButtonRelease: - if (mouseReleaseEvent(static_cast<QMouseEvent*>(event))) - return true; - break; - case QEvent::KeyPress: - if (keyPressEvent(static_cast<QKeyEvent*>(event))) - return true; - break; - case QEvent::KeyRelease: - if (keyReleaseEvent(static_cast<QKeyEvent*>(event))) - return true; - break; - case QEvent::MouseButtonDblClick: - if (mouseDoubleClickEvent(static_cast<QMouseEvent*>(event))) - return true; - break; -#ifndef QT_NO_WHEELEVENT - case QEvent::Wheel: - if (wheelEvent(static_cast<QWheelEvent*>(event))) - return true; - break; -#endif - case QEvent::TouchBegin: - case QEvent::TouchUpdate: - case QEvent::TouchEnd: - if (touchEvent(static_cast<QTouchEvent*>(event))) - return true; - break; - default: - break; - } - - return QObject::eventFilter(obj, event); -} - -bool AbstractViewInspector::leaveEvent(QEvent *event) -{ - foreach (AbstractTool *tool, m_tools) - tool->leaveEvent(event); - return true; -} - -bool AbstractViewInspector::mousePressEvent(QMouseEvent *event) -{ - foreach (AbstractTool *tool, m_tools) - tool->mousePressEvent(event); - return true; -} - -bool AbstractViewInspector::mouseMoveEvent(QMouseEvent *event) -{ - if (event->buttons()) { - foreach (AbstractTool *tool, m_tools) - tool->mouseMoveEvent(event); - } else { - foreach (AbstractTool *tool, m_tools) - tool->hoverMoveEvent(event); - } - return true; -} - -bool AbstractViewInspector::mouseReleaseEvent(QMouseEvent *event) -{ - foreach (AbstractTool *tool, m_tools) - tool->mouseReleaseEvent(event); - return true; -} - -bool AbstractViewInspector::keyPressEvent(QKeyEvent *event) -{ - foreach (AbstractTool *tool, m_tools) - tool->keyPressEvent(event); - return true; -} - -bool AbstractViewInspector::keyReleaseEvent(QKeyEvent *event) -{ - foreach (AbstractTool *tool, m_tools) - tool->keyReleaseEvent(event); - return true; -} - -bool AbstractViewInspector::mouseDoubleClickEvent(QMouseEvent *event) -{ - foreach (AbstractTool *tool, m_tools) - tool->mouseDoubleClickEvent(event); - return true; -} - -#ifndef QT_NO_WHEELEVENT -bool AbstractViewInspector::wheelEvent(QWheelEvent *event) -{ - foreach (AbstractTool *tool, m_tools) - tool->wheelEvent(event); - return true; -} -#endif - -bool AbstractViewInspector::touchEvent(QTouchEvent *event) -{ - foreach (AbstractTool *tool, m_tools) - tool->touchEvent(event); - return true; -} - -void AbstractViewInspector::onQmlObjectDestroyed(QObject *object) -{ - if (!m_hashObjectsTobeDestroyed.contains(object)) - return; - - QPair<int, int> ids = m_hashObjectsTobeDestroyed.take(object); - - QByteArray response; - - QQmlDebugStream rs(&response, QIODevice::WriteOnly); - rs << QByteArray(RESPONSE) << ids.first << true << ids.second; - - emit m_debugService->messageToClient(m_debugService->name(), response); -} - -void AbstractViewInspector::handleMessage(const QByteArray &message) -{ - bool success = true; - QQmlDebugStream ds(message); - - QByteArray type; - ds >> type; - - int requestId = -1; - if (type == REQUEST) { - QByteArray command; - ds >> requestId >> command; - - if (command == ENABLE) { - setEnabled(true); - - } else if (command == DISABLE) { - setEnabled(false); - - } else if (command == SELECT) { - QList<int> debugIds; - ds >> debugIds; - - QList<QObject*> selectedObjects; - foreach (int debugId, debugIds) { - if (QObject *obj = QQmlDebugService::objectForId(debugId)) - selectedObjects << obj; - } - if (m_enabled) - changeCurrentObjects(selectedObjects); - - } else if (command == RELOAD) { - QHash<QString, QByteArray> changesHash; - ds >> changesHash; - m_reloadEventId = requestId; - reloadQmlFile(changesHash); - return; - - } else if (command == SET_ANIMATION_SPEED) { - qreal speed; - ds >> speed; - setAnimationSpeed(speed); - - } else if (command == SHOW_APP_ON_TOP) { - bool showOnTop; - ds >> showOnTop; - setShowAppOnTop(showOnTop); - - } else if (command == CREATE_OBJECT) { - QString qml; - int parentId; - QString filename; - QStringList imports; - ds >> qml >> parentId >> imports >> filename; - createQmlObject(qml, QQmlDebugService::objectForId(parentId), - imports, filename); - - } else if (command == DESTROY_OBJECT) { - int debugId; - ds >> debugId; - if (QObject *obj = QQmlDebugService::objectForId(debugId)) { - QPair<int, int> ids(requestId, debugId); - m_hashObjectsTobeDestroyed.insert(obj, ids); - connect(obj, SIGNAL(destroyed(QObject*)), SLOT(onQmlObjectDestroyed(QObject*))); - obj->deleteLater(); - } - return; - - } else if (command == MOVE_OBJECT) { - int debugId, newParent; - ds >> debugId >> newParent; - reparentQmlObject(QQmlDebugService::objectForId(debugId), - QQmlDebugService::objectForId(newParent)); - - } else if (command == CLEAR_CACHE) { - clearComponentCache(); - - } else { - qWarning() << "Warning: Not handling command:" << command; - success = false; - - } - } else { - qWarning() << "Warning: Not handling type:" << type << REQUEST; - success = false; - - } - - QByteArray response; - QQmlDebugStream rs(&response, QIODevice::WriteOnly); - rs << QByteArray(RESPONSE) << requestId << success; - emit m_debugService->messageToClient(m_debugService->name(), response); -} - -void AbstractViewInspector::sendCurrentObjects(const QList<QObject*> &objects) -{ - QByteArray message; - QQmlDebugStream ds(&message, QIODevice::WriteOnly); - - ds << QByteArray(EVENT) << m_eventId++ << QByteArray(SELECT); - - QList<int> debugIds; - debugIds.reserve(objects.count()); - foreach (QObject *object, objects) - debugIds << QQmlDebugService::idForObject(object); - ds << debugIds; - - emit m_debugService->messageToClient(m_debugService->name(), message); -} - -void AbstractViewInspector::sendQmlFileReloaded(bool success) -{ - if (m_reloadEventId == -1) - return; - - QByteArray response; - - QQmlDebugStream rs(&response, QIODevice::WriteOnly); - rs << QByteArray(RESPONSE) << m_reloadEventId << success; - - emit m_debugService->messageToClient(m_debugService->name(), response); -} - -QString AbstractViewInspector::idStringForObject(QObject *obj) const -{ - QQmlContext *context = qmlContext(obj); - if (context) { - QQmlContextData *cdata = QQmlContextData::get(context); - if (cdata) - return cdata->findObjectId(obj); - } - return QString(); -} - -void AbstractViewInspector::appendTool(AbstractTool *tool) -{ - m_tools.append(tool); -} - -void AbstractViewInspector::removeTool(AbstractTool *tool) -{ - m_tools.removeOne(tool); -} - -} // namespace QmlJSDebugger - -QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_inspector/abstractviewinspector.h b/src/plugins/qmltooling/qmldbg_inspector/abstractviewinspector.h deleted file mode 100644 index 8f7ad4ac5b..0000000000 --- a/src/plugins/qmltooling/qmldbg_inspector/abstractviewinspector.h +++ /dev/null @@ -1,126 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef ABSTRACTVIEWINSPECTOR_H -#define ABSTRACTVIEWINSPECTOR_H - -#include <QtCore/QHash> -#include <QtCore/QObject> -#include <QtCore/QStringList> - -QT_BEGIN_NAMESPACE -class QQmlEngine; -class QQmlDebugService; -class QKeyEvent; -class QMouseEvent; -class QWheelEvent; -class QTouchEvent; - -namespace QmlJSDebugger { - -class AbstractTool; - -/* - * The common code between QQuickView and QQuickView inspectors lives here, - */ -class AbstractViewInspector : public QObject -{ - Q_OBJECT - -public: - explicit AbstractViewInspector(QQmlDebugService *service, QObject *parent = 0); - - void handleMessage(const QByteArray &message); - - void createQmlObject(const QString &qml, QObject *parent, - const QStringList &importList, - const QString &filename = QString()); - void clearComponentCache(); - - bool enabled() const { return m_enabled; } - - void sendCurrentObjects(const QList<QObject*> &); - - void sendQmlFileReloaded(bool success); - - QString idStringForObject(QObject *obj) const; - - virtual void changeCurrentObjects(const QList<QObject*> &objects) = 0; - virtual void reparentQmlObject(QObject *object, QObject *newParent) = 0; - virtual Qt::WindowFlags windowFlags() const = 0; - virtual void setWindowFlags(Qt::WindowFlags flags) = 0; - virtual QQmlEngine *declarativeEngine() const = 0; - virtual void reloadQmlFile(const QHash<QString, QByteArray> &changesHash) = 0; - - void appendTool(AbstractTool *tool); - void removeTool(AbstractTool *tool); - -protected: - bool eventFilter(QObject *, QEvent *); - - virtual bool leaveEvent(QEvent *); - virtual bool mousePressEvent(QMouseEvent *event); - virtual bool mouseMoveEvent(QMouseEvent *event); - virtual bool mouseReleaseEvent(QMouseEvent *event); - virtual bool keyPressEvent(QKeyEvent *event); - virtual bool keyReleaseEvent(QKeyEvent *keyEvent); - virtual bool mouseDoubleClickEvent(QMouseEvent *event); -#ifndef QT_NO_WHEELEVENT - virtual bool wheelEvent(QWheelEvent *event); -#endif - virtual bool touchEvent(QTouchEvent *event); - virtual void setShowAppOnTop(bool) = 0; - -private slots: - void onQmlObjectDestroyed(QObject *object); - -private: - void setEnabled(bool value); - - void setAnimationSpeed(qreal factor); - - bool m_enabled; - - QQmlDebugService *m_debugService; - QList<AbstractTool *> m_tools; - int m_eventId; - int m_reloadEventId; - // Hash< object to be destroyed, QPair<destroy eventId, object debugId> > - QHash<QObject *, QPair<int, int> > m_hashObjectsTobeDestroyed; -}; - -} // namespace QmlJSDebugger - -QT_END_NAMESPACE - -#endif // ABSTRACTVIEWINSPECTOR_H diff --git a/src/plugins/qmltooling/qmldbg_inspector/globalinspector.cpp b/src/plugins/qmltooling/qmldbg_inspector/globalinspector.cpp new file mode 100644 index 0000000000..2150b68f32 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_inspector/globalinspector.cpp @@ -0,0 +1,406 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "globalinspector.h" +#include "highlight.h" +#include "inspecttool.h" +#include "qqmldebugpacket.h" + +#include <private/qqmldebugserviceinterfaces_p.h> +#include <private/qabstractanimation_p.h> +#include <private/qqmlcomponent_p.h> + +#include <QtGui/qwindow.h> + +//INSPECTOR SERVICE PROTOCOL +// <HEADER><COMMAND><DATA> +// <HEADER> : <type{request, response, event}><requestId/eventId>[<response_success_bool>] +// <COMMAND> : {"enable", "disable", "select", "setAnimationSpeed", +// "showAppOnTop", "createObject", "destroyObject", "moveObject"} +// <DATA> : select: <debugIds_int_list> +// setAnimationSpeed: <speed_real> +// showAppOnTop: <set_bool> +// createObject: <qml_string><parentId_int><imports_string_list><filename_string> +// destroyObject: <debugId_int> +// moveObject: <debugId_int><newParentId_int> +// Response for "destroyObject" carries the <debugId_int> of the destroyed object. + +QT_BEGIN_NAMESPACE + +const char REQUEST[] = "request"; +const char RESPONSE[] = "response"; +const char EVENT[] = "event"; +const char ENABLE[] = "enable"; +const char DISABLE[] = "disable"; +const char SELECT[] = "select"; +const char SET_ANIMATION_SPEED[] = "setAnimationSpeed"; +const char SHOW_APP_ON_TOP[] = "showAppOnTop"; +const char CREATE_OBJECT[] = "createObject"; +const char DESTROY_OBJECT[] = "destroyObject"; +const char MOVE_OBJECT[] = "moveObject"; + +namespace QmlJSDebugger { + +void GlobalInspector::removeFromSelectedItems(QObject *object) +{ + if (QQuickItem *item = qobject_cast<QQuickItem*>(object)) { + if (m_selectedItems.removeOne(item)) + delete m_highlightItems.take(item); + } +} + +void GlobalInspector::setSelectedItems(const QList<QQuickItem *> &items) +{ + if (!syncSelectedItems(items)) + return; + + QList<QObject*> objectList; + objectList.reserve(items.count()); + foreach (QQuickItem *item, items) + objectList << item; + + sendCurrentObjects(objectList); +} + +void GlobalInspector::showSelectedItemName(QQuickItem *item, const QPointF &point) +{ + SelectionHighlight *highlightItem = m_highlightItems.value(item, 0); + if (highlightItem) + highlightItem->showName(point); +} + +void GlobalInspector::sendCurrentObjects(const QList<QObject*> &objects) +{ + QQmlDebugPacket ds; + + ds << QByteArray(EVENT) << m_eventId++ << QByteArray(SELECT); + + QList<int> debugIds; + debugIds.reserve(objects.count()); + foreach (QObject *object, objects) + debugIds << QQmlDebugService::idForObject(object); + ds << debugIds; + + emit messageToClient(QQmlInspectorService::s_key, ds.data()); +} + +static bool reparentQmlObject(QObject *object, QObject *newParent) +{ + if (!newParent) + return false; + + object->setParent(newParent); + QQuickItem *newParentItem = qobject_cast<QQuickItem*>(newParent); + QQuickItem *item = qobject_cast<QQuickItem*>(object); + if (newParentItem && item) + item->setParentItem(newParentItem); + return true; +} + +class ObjectCreator : public QObject +{ + Q_OBJECT +public: + ObjectCreator(int requestId, QQmlEngine *engine, QObject *parent) : + QObject(parent), m_component(engine), m_requestId(requestId) + { + connect(&m_component, &QQmlComponent::statusChanged, this, &ObjectCreator::tryCreateObject); + } + + void run(const QByteArray &qml, const QUrl &filename) + { + m_component.setData(qml, filename); + } + +signals: + void result(int requestId, bool success); + +public slots: + void tryCreateObject(QQmlComponent::Status status) + { + switch (status) { + case QQmlComponent::Error: + emit result(m_requestId, false); + delete this; + return; + case QQmlComponent::Ready: { + // Stuff might have changed. We have to lookup the parentContext again. + QQmlContext *parentContext = QQmlEngine::contextForObject(parent()); + if (!parentContext) { + emit result(m_requestId, false); + } else { + QObject *newObject = m_component.create(parentContext); + if (newObject && reparentQmlObject(newObject, parent())) + emit result(m_requestId, true); + else + emit result(m_requestId, false); + } + delete this; + return; + } + default: + break; + } + } + +private: + QQmlComponent m_component; + int m_requestId; +}; + +bool GlobalInspector::createQmlObject(int requestId, const QString &qml, QObject *parent, + const QStringList &importList, const QString &filename) +{ + if (!parent) + return false; + + QQmlContext *parentContext = QQmlEngine::contextForObject(parent); + if (!parentContext) + return false; + + QString imports; + foreach (const QString &s, importList) + imports += s + QLatin1Char('\n'); + + ObjectCreator *objectCreator = new ObjectCreator(requestId, parentContext->engine(), parent); + connect(objectCreator, &ObjectCreator::result, this, &GlobalInspector::sendResult); + objectCreator->run((imports + qml).toUtf8(), QUrl::fromLocalFile(filename)); + return true; +} + +void GlobalInspector::addWindow(QQuickWindow *window) +{ + m_windowInspectors.append(new QQuickWindowInspector(window, this)); +} + +void GlobalInspector::removeWindow(QQuickWindow *window) +{ + for (QList<QmlJSDebugger::QQuickWindowInspector *>::Iterator i = m_windowInspectors.begin(); + i != m_windowInspectors.end();) { + if ((*i)->quickWindow() == window) { + delete *i; + i = m_windowInspectors.erase(i); + } else { + ++i; + } + } +} + +void GlobalInspector::setParentWindow(QQuickWindow *window, QWindow *parentWindow) +{ + foreach (QmlJSDebugger::QQuickWindowInspector *inspector, m_windowInspectors) { + if (inspector->quickWindow() == window) + inspector->setParentWindow(parentWindow); + } +} + +bool GlobalInspector::syncSelectedItems(const QList<QQuickItem *> &items) +{ + bool selectionChanged = false; + + // Disconnect and remove items that are no longer selected + foreach (const QPointer<QQuickItem> &item, m_selectedItems) { + if (!item) // Don't see how this can happen due to handling of destroyed() + continue; + if (items.contains(item)) + continue; + + selectionChanged = true; + item->disconnect(this); + m_selectedItems.removeOne(item); + delete m_highlightItems.take(item); + } + + // Connect and add newly selected items + foreach (QQuickItem *item, items) { + if (m_selectedItems.contains(item)) + continue; + + selectionChanged = true; + connect(item, &QObject::destroyed, this, &GlobalInspector::removeFromSelectedItems); + m_selectedItems.append(item); + foreach (QQuickWindowInspector *inspector, m_windowInspectors) { + if (inspector->isEnabled() && inspector->quickWindow() == item->window()) { + m_highlightItems.insert(item, new SelectionHighlight(titleForItem(item), item, + inspector->overlay())); + break; + } + } + } + + return selectionChanged; +} + +QString GlobalInspector::titleForItem(QQuickItem *item) const +{ + QString className = QLatin1String(item->metaObject()->className()); + QString objectStringId = idStringForObject(item); + + className.remove(QRegExp(QLatin1String("_QMLTYPE_\\d+"))); + className.remove(QRegExp(QLatin1String("_QML_\\d+"))); + if (className.startsWith(QLatin1String("QQuick"))) + className = className.mid(6); + + QString constructedName; + + if (!objectStringId.isEmpty()) { + constructedName = objectStringId + QLatin1String(" (") + className + QLatin1Char(')'); + } else if (!item->objectName().isEmpty()) { + constructedName = item->objectName() + QLatin1String(" (") + className + QLatin1Char(')'); + } else { + constructedName = className; + } + + return constructedName; +} + +QString GlobalInspector::idStringForObject(QObject *obj) const +{ + QQmlContext *context = qmlContext(obj); + if (context) { + QQmlContextData *cdata = QQmlContextData::get(context); + if (cdata) + return cdata->findObjectId(obj); + } + return QString(); +} + +void GlobalInspector::processMessage(const QByteArray &message) +{ + bool success = true; + QQmlDebugPacket ds(message); + + QByteArray type; + ds >> type; + + int requestId = -1; + if (type == REQUEST) { + QByteArray command; + ds >> requestId >> command; + + if (command == ENABLE) { + foreach (QQuickWindowInspector *inspector, m_windowInspectors) + inspector->setEnabled(true); + success = !m_windowInspectors.isEmpty(); + } else if (command == DISABLE) { + setSelectedItems(QList<QQuickItem*>()); + foreach (QQuickWindowInspector *inspector, m_windowInspectors) + inspector->setEnabled(false); + success = !m_windowInspectors.isEmpty(); + } else if (command == SELECT) { + QList<int> debugIds; + ds >> debugIds; + + QList<QQuickItem *> selectedObjects; + foreach (int debugId, debugIds) { + if (QQuickItem *obj = + qobject_cast<QQuickItem *>(QQmlDebugService::objectForId(debugId))) + selectedObjects << obj; + } + syncSelectedItems(selectedObjects); + } else if (command == SET_ANIMATION_SPEED) { + qreal speed; + ds >> speed; + QUnifiedTimer::instance()->setSlowModeEnabled(speed != 1.0); + QUnifiedTimer::instance()->setSlowdownFactor(speed); + } else if (command == SHOW_APP_ON_TOP) { + bool showOnTop; + ds >> showOnTop; + foreach (QmlJSDebugger::QQuickWindowInspector *inspector, m_windowInspectors) + inspector->setShowAppOnTop(showOnTop); + success = !m_windowInspectors.isEmpty(); + } else if (command == CREATE_OBJECT) { + QString qml; + int parentId; + QString filename; + QStringList imports; + ds >> qml >> parentId >> imports >> filename; + if (QObject *parent = QQmlDebugService::objectForId(parentId)) { + if (createQmlObject(requestId, qml, parent, imports, filename)) + return; // will callback for result + else { + success = false; + } + } else { + success = false; + } + + } else if (command == DESTROY_OBJECT) { + int debugId; + ds >> debugId; + if (QObject *obj = QQmlDebugService::objectForId(debugId)) + delete obj; + else + success = false; + + } else if (command == MOVE_OBJECT) { + int debugId, newParent; + ds >> debugId >> newParent; + success = reparentQmlObject(QQmlDebugService::objectForId(debugId), + QQmlDebugService::objectForId(newParent)); + } else { + qWarning() << "Warning: Not handling command:" << command; + success = false; + } + } else { + qWarning() << "Warning: Not handling type:" << type << REQUEST; + success = false; + } + + sendResult(requestId, success); +} + +void GlobalInspector::sendResult(int requestId, bool success) +{ + QQmlDebugPacket rs; + rs << QByteArray(RESPONSE) << requestId << success; + emit messageToClient(QQmlInspectorService::s_key, rs.data()); +} + +GlobalInspector::~GlobalInspector() +{ + // Everything else is parented + qDeleteAll(m_highlightItems); +} + +} + +QT_END_NAMESPACE + +#include <globalinspector.moc> diff --git a/src/plugins/qmltooling/qmldbg_inspector/globalinspector.h b/src/plugins/qmltooling/qmldbg_inspector/globalinspector.h new file mode 100644 index 0000000000..7bbe6d6aa2 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_inspector/globalinspector.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef GLOBALINSPECTOR_H +#define GLOBALINSPECTOR_H + +#include "qquickwindowinspector.h" + +#include <QtCore/QObject> +#include <QtCore/QPointer> +#include <QtCore/QHash> +#include <QtQuick/QQuickItem> + +QT_BEGIN_NAMESPACE + +namespace QmlJSDebugger { + +class SelectionHighlight; + +class GlobalInspector : public QObject +{ + Q_OBJECT +public: + GlobalInspector(QObject *parent = 0) : QObject(parent), m_eventId(0) {} + ~GlobalInspector(); + + void setSelectedItems(const QList<QQuickItem *> &items); + void showSelectedItemName(QQuickItem *item, const QPointF &point); + + void addWindow(QQuickWindow *window); + void setParentWindow(QQuickWindow *window, QWindow *parentWindow); + void setQmlEngine(QQuickWindow *window, QQmlEngine *engine); + void removeWindow(QQuickWindow *window); + void processMessage(const QByteArray &message); + +signals: + void messageToClient(const QString &name, const QByteArray &data); + +private slots: + void sendResult(int requestId, bool success); + +private: + void sendCurrentObjects(const QList<QObject *> &objects); + void removeFromSelectedItems(QObject *object); + QString titleForItem(QQuickItem *item) const; + QString idStringForObject(QObject *obj) const; + bool createQmlObject(int requestId, const QString &qml, QObject *parent, + const QStringList &importList, const QString &filename); + bool destroyQmlObject(QObject *object, int requestId, int debugId); + bool syncSelectedItems(const QList<QQuickItem *> &items); + + // Hash< object to be destroyed, QPair<destroy eventId, object debugId> > + QList<QPointer<QQuickItem> > m_selectedItems; + QHash<QQuickItem *, SelectionHighlight *> m_highlightItems; + QList<QQuickWindowInspector *> m_windowInspectors; + int m_eventId; +}; + +} // QmlJSDebugger + +QT_END_NAMESPACE + +#endif // GLOBALINSPECTOR_H diff --git a/src/plugins/qmltooling/qmldbg_inspector/highlight.cpp b/src/plugins/qmltooling/qmldbg_inspector/highlight.cpp index 4d4e3aa720..26eb0f8ed8 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/highlight.cpp +++ b/src/plugins/qmltooling/qmldbg_inspector/highlight.cpp @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/qmltooling/qmldbg_inspector/highlight.h b/src/plugins/qmltooling/qmldbg_inspector/highlight.h index 05f6382353..4a85cb4d50 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/highlight.h +++ b/src/plugins/qmltooling/qmldbg_inspector/highlight.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/qmltooling/qmldbg_inspector/inspecttool.cpp b/src/plugins/qmltooling/qmldbg_inspector/inspecttool.cpp index cc6b4ffb8c..7527bc41c7 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/inspecttool.cpp +++ b/src/plugins/qmltooling/qmldbg_inspector/inspecttool.cpp @@ -1,45 +1,50 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "inspecttool.h" - #include "highlight.h" -#include "qquickviewinspector.h" +#include "qquickwindowinspector.h" +#include "globalinspector.h" #include <QtCore/QLineF> #include <QtGui/QMouseEvent> -#include <QtGui/QWheelEvent> #include <QtGui/QTouchEvent> #include <QtGui/QKeyEvent> #include <QtGui/QGuiApplication> @@ -52,61 +57,23 @@ QT_BEGIN_NAMESPACE namespace QmlJSDebugger { -static const double ZoomSnapDelta = 0.04; -static const int PressAndHoldTimeout = 800; - -InspectTool::InspectTool(QQuickViewInspector *inspector, QQuickView *view) : - AbstractTool(inspector), - m_originalSmooth(view->contentItem()->smooth()), - m_dragStarted(false), - m_pinchStarted(false), - m_didPressAndHold(false), - m_tapEvent(false), +InspectTool::InspectTool(QQuickWindowInspector *inspector, QQuickWindow *view) : + QObject(inspector), m_contentItem(view->contentItem()), - m_originalPosition(view->contentItem()->position()), - m_smoothScaleFactor(ZoomSnapDelta), - m_minScale(0.125f), - m_maxScale(48.0f), - m_originalScale(view->contentItem()->scale()), m_touchTimestamp(0), m_hoverHighlight(new HoverHighlight(inspector->overlay())), m_lastItem(0), m_lastClickedItem(0) { - //Press and Hold Timer - m_pressAndHoldTimer.setSingleShot(true); - m_pressAndHoldTimer.setInterval(PressAndHoldTimeout); - connect(&m_pressAndHoldTimer, SIGNAL(timeout()), SLOT(zoomTo100())); //Timer to display selected item's name m_nameDisplayTimer.setSingleShot(true); m_nameDisplayTimer.setInterval(QGuiApplication::styleHints()->mouseDoubleClickInterval()); - connect(&m_nameDisplayTimer, SIGNAL(timeout()), SLOT(showSelectedItemName())); - enable(true); + connect(&m_nameDisplayTimer, &QTimer::timeout, this, &InspectTool::showItemName); } -InspectTool::~InspectTool() +void InspectTool::enterEvent(QEvent *) { - enable(false); -} - -void InspectTool::enable(bool enable) -{ - if (!enable) { - inspector()->setSelectedItems(QList<QQuickItem*>()); - // restoring the original states. - if (m_contentItem) { - m_contentItem->setScale(m_originalScale); - m_contentItem->setPosition(m_originalPosition); - m_contentItem->setSmooth(m_originalSmooth); - } - } else { - if (m_contentItem) { - m_originalSmooth = m_contentItem->smooth(); - m_originalScale = m_contentItem->scale(); - m_originalPosition = m_contentItem->position(); - m_contentItem->setSmooth(true); - } - } + m_hoverHighlight->setVisible(true); } void InspectTool::leaveEvent(QEvent *) @@ -118,16 +85,6 @@ void InspectTool::mousePressEvent(QMouseEvent *event) { m_mousePosition = event->localPos(); if (event->button() == Qt::LeftButton) { - m_pressAndHoldTimer.start(); - initializeDrag(event->localPos()); - } -} - -void InspectTool::mouseReleaseEvent(QMouseEvent *event) -{ - m_mousePosition = event->localPos(); - m_pressAndHoldTimer.stop(); - if (event->button() == Qt::LeftButton && !m_dragStarted) { selectItem(); m_hoverHighlight->setVisible(false); } @@ -136,7 +93,6 @@ void InspectTool::mouseReleaseEvent(QMouseEvent *event) void InspectTool::mouseDoubleClickEvent(QMouseEvent *event) { m_mousePosition = event->localPos(); - m_pressAndHoldTimer.stop(); if (event->button() == Qt::LeftButton) { selectNextItem(); m_hoverHighlight->setVisible(false); @@ -145,14 +101,12 @@ void InspectTool::mouseDoubleClickEvent(QMouseEvent *event) void InspectTool::mouseMoveEvent(QMouseEvent *event) { - m_mousePosition = event->localPos(); - moveItem(event->buttons() & Qt::LeftButton); + hoverMoveEvent(event); } void InspectTool::hoverMoveEvent(QMouseEvent *event) { m_mousePosition = event->localPos(); - m_pressAndHoldTimer.stop(); QQuickItem *item = inspector()->topVisibleItemAt(event->pos()); if (!item || item == m_lastClickedItem) { m_hoverHighlight->setVisible(false); @@ -162,54 +116,6 @@ void InspectTool::hoverMoveEvent(QMouseEvent *event) } } -#ifndef QT_NO_WHEELEVENT -void InspectTool::wheelEvent(QWheelEvent *event) -{ - if (event->orientation() != Qt::Vertical) - return; - - Qt::KeyboardModifier smoothZoomModifier = Qt::ControlModifier; - if (event->modifiers() & smoothZoomModifier) { - int numDegrees = event->delta() / 8; - qreal newScale = m_contentItem->scale() + m_smoothScaleFactor * (numDegrees / 15.0f); - scaleView(newScale / m_contentItem->scale(), m_mousePosition, m_mousePosition); - } else if (!event->modifiers()) { - if (event->delta() > 0) { - zoomIn(); - } else if (event->delta() < 0) { - zoomOut(); - } - } -} -#endif - -void InspectTool::keyReleaseEvent(QKeyEvent *event) -{ - switch (event->key()) { - case Qt::Key_Plus: - zoomIn(); - break; - case Qt::Key_Minus: - zoomOut(); - break; - case Qt::Key_1: - case Qt::Key_2: - case Qt::Key_3: - case Qt::Key_4: - case Qt::Key_5: - case Qt::Key_6: - case Qt::Key_7: - case Qt::Key_8: - case Qt::Key_9: { - qreal newScale = ((event->key() - Qt::Key_0) * 1.0f); - scaleView(newScale / m_contentItem->scale(), m_mousePosition, m_mousePosition); - break; - } - default: - break; - } -} - void InspectTool::touchEvent(QTouchEvent *event) { QList<QTouchEvent::TouchPoint> touchPoints = event->touchPoints(); @@ -217,10 +123,7 @@ void InspectTool::touchEvent(QTouchEvent *event) switch (event->type()) { case QEvent::TouchBegin: if (touchPoints.count() == 1 && (event->touchPointStates() & Qt::TouchPointPressed)) { - if (!m_pressAndHoldTimer.isActive()) - m_pressAndHoldTimer.start(); m_mousePosition = touchPoints.first().pos(); - initializeDrag(touchPoints.first().pos()); m_tapEvent = true; } else { m_tapEvent = false; @@ -229,48 +132,23 @@ void InspectTool::touchEvent(QTouchEvent *event) case QEvent::TouchUpdate: { if (touchPoints.count() > 1) m_tapEvent = false; - if ((touchPoints.count() == 1) - && (event->touchPointStates() & Qt::TouchPointMoved)) { + else if ((touchPoints.count() == 1) && (event->touchPointStates() & Qt::TouchPointMoved)) m_mousePosition = touchPoints.first().pos(); - moveItem(true); - } else if ((touchPoints.count() == 2) - && (!(event->touchPointStates() & Qt::TouchPointReleased))) { - // determine scale factor - const QTouchEvent::TouchPoint &touchPoint0 = touchPoints.first(); - const QTouchEvent::TouchPoint &touchPoint1 = touchPoints.last(); - - qreal touchScaleFactor = - QLineF(touchPoint0.pos(), touchPoint1.pos()).length() - / QLineF(touchPoint0.lastPos(), touchPoint1.lastPos()).length(); - - QPointF oldcenter = (touchPoint0.lastPos() + touchPoint1.lastPos()) / 2; - QPointF newcenter = (touchPoint0.pos() + touchPoint1.pos()) / 2; - - m_pinchStarted = true; - scaleView(touchScaleFactor, newcenter, oldcenter); - } break; } case QEvent::TouchEnd: { - m_pressAndHoldTimer.stop(); - if (m_pinchStarted) { - m_pinchStarted = false; - } - if (touchPoints.count() == 1 && !m_dragStarted && - !m_didPressAndHold && m_tapEvent) { + if (touchPoints.count() == 1 && m_tapEvent) { m_tapEvent = false; bool doubleTap = event->timestamp() - m_touchTimestamp < static_cast<ulong>(QGuiApplication::styleHints()->mouseDoubleClickInterval()); if (doubleTap) { m_nameDisplayTimer.stop(); selectNextItem(); - } - else { + } else { selectItem(); } m_touchTimestamp = event->timestamp(); } - m_didPressAndHold = false; break; } default: @@ -278,108 +156,6 @@ void InspectTool::touchEvent(QTouchEvent *event) } } -void InspectTool::scaleView(const qreal &factor, const QPointF &newcenter, const QPointF &oldcenter) -{ - m_pressAndHoldTimer.stop(); - if (((m_contentItem->scale() * factor) > m_maxScale) - || ((m_contentItem->scale() * factor) < m_minScale)) { - return; - } - //New position = new center + scalefactor * (oldposition - oldcenter) - QPointF newPosition = newcenter + (factor * (m_contentItem->position() - oldcenter)); - m_contentItem->setScale(m_contentItem->scale() * factor); - m_contentItem->setPosition(newPosition); -} - -void InspectTool::zoomIn() -{ - qreal newScale = nextZoomScale(ZoomIn); - scaleView(newScale / m_contentItem->scale(), m_mousePosition, m_mousePosition); -} - -void InspectTool::zoomOut() -{ - qreal newScale = nextZoomScale(ZoomOut); - scaleView(newScale / m_contentItem->scale(), m_mousePosition, m_mousePosition); -} - -void InspectTool::zoomTo100() -{ - m_didPressAndHold = true; - - m_contentItem->setPosition(QPointF(0, 0)); - m_contentItem->setScale(1.0); -} - -qreal InspectTool::nextZoomScale(ZoomDirection direction) -{ - static QList<qreal> zoomScales = - QList<qreal>() - << 0.125f - << 1.0f / 6.0f - << 0.25f - << 1.0f / 3.0f - << 0.5f - << 2.0f / 3.0f - << 1.0f - << 2.0f - << 3.0f - << 4.0f - << 5.0f - << 6.0f - << 7.0f - << 8.0f - << 12.0f - << 16.0f - << 32.0f - << 48.0f; - - if (direction == ZoomIn) { - for (int i = 0; i < zoomScales.length(); ++i) { - if (zoomScales[i] > m_contentItem->scale()) - return zoomScales[i]; - } - return zoomScales.last(); - } else { - for (int i = zoomScales.length() - 1; i >= 0; --i) { - if (zoomScales[i] < m_contentItem->scale()) - return zoomScales[i]; - } - return zoomScales.first(); - } - - return 1.0f; -} - -void InspectTool::initializeDrag(const QPointF &pos) -{ - m_dragStartPosition = pos; - m_dragStarted = false; -} - -void InspectTool::dragItemToPosition() -{ - QPointF newPosition = m_contentItem->position() + m_mousePosition - m_dragStartPosition; - m_dragStartPosition = m_mousePosition; - m_contentItem->setPosition(newPosition); -} - -void InspectTool::moveItem(bool valid) -{ - if (m_pinchStarted) - return; - - if (!m_dragStarted - && valid - && ((m_dragStartPosition - m_mousePosition).manhattanLength() - > QGuiApplication::styleHints()->startDragDistance())) { - m_pressAndHoldTimer.stop(); - m_dragStarted = true; - } - if (m_dragStarted) - dragItemToPosition(); -} - void InspectTool::selectNextItem() { if (m_lastClickedItem != inspector()->topVisibleItemAt(m_mousePosition)) @@ -391,8 +167,8 @@ void InspectTool::selectNextItem() m_lastItem = items[i+1]; else m_lastItem = items[0]; - inspector()->setSelectedItems(QList<QQuickItem*>() << m_lastItem); - showSelectedItemName(); + globalInspector()->setSelectedItems(QList<QQuickItem*>() << m_lastItem); + showItemName(); break; } } @@ -402,24 +178,29 @@ void InspectTool::selectItem() { if (!inspector()->topVisibleItemAt(m_mousePosition)) return; + m_lastClickedItem = inspector()->topVisibleItemAt(m_mousePosition); + m_lastItem = m_lastClickedItem; + globalInspector()->setSelectedItems(QList<QQuickItem*>() << m_lastClickedItem); if (m_lastClickedItem == inspector()->topVisibleItemAt(m_mousePosition)) { m_nameDisplayTimer.start(); - return; + } else { + showItemName(); } - m_lastClickedItem = inspector()->topVisibleItemAt(m_mousePosition); - m_lastItem = m_lastClickedItem; - inspector()->setSelectedItems(QList<QQuickItem*>() << m_lastClickedItem); - showSelectedItemName(); } -QQuickViewInspector *InspectTool::inspector() const +void InspectTool::showItemName() +{ + globalInspector()->showSelectedItemName(m_lastItem, m_mousePosition); +} + +QQuickWindowInspector *InspectTool::inspector() const { - return static_cast<QQuickViewInspector*>(AbstractTool::inspector()); + return static_cast<QQuickWindowInspector *>(parent()); } -void InspectTool::showSelectedItemName() +GlobalInspector *InspectTool::globalInspector() const { - inspector()->showSelectedItemName(m_lastItem, m_mousePosition); + return static_cast<GlobalInspector *>(parent()->parent()); } } // namespace QmlJSDebugger diff --git a/src/plugins/qmltooling/qmldbg_inspector/inspecttool.h b/src/plugins/qmltooling/qmldbg_inspector/inspecttool.h index fdb763d4b3..933c162dad 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/inspecttool.h +++ b/src/plugins/qmltooling/qmldbg_inspector/inspecttool.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -34,85 +40,52 @@ #ifndef INSPECTTOOL_H #define INSPECTTOOL_H -#include "abstracttool.h" - #include <QtCore/QPointF> #include <QtCore/QPointer> #include <QtCore/QTimer> QT_BEGIN_NAMESPACE -class QQuickView; +class QQuickWindow; class QQuickItem; +class QMouseEvent; +class QKeyEvent; +class QTouchEvent; namespace QmlJSDebugger { -class QQuickViewInspector; +class GlobalInspector; +class QQuickWindowInspector; class HoverHighlight; -class InspectTool : public AbstractTool +class InspectTool : public QObject { Q_OBJECT public: - enum ZoomDirection { - ZoomIn, - ZoomOut - }; - - InspectTool(QQuickViewInspector *inspector, QQuickView *view); - ~InspectTool(); - - void enable(bool enable); + InspectTool(QQuickWindowInspector *inspector, QQuickWindow *view); + void enterEvent(QEvent *); void leaveEvent(QEvent *); - void mousePressEvent(QMouseEvent *); void mouseMoveEvent(QMouseEvent *); - void mouseReleaseEvent(QMouseEvent *); void mouseDoubleClickEvent(QMouseEvent *); - void hoverMoveEvent(QMouseEvent *); -#ifndef QT_NO_WHEELEVENT - void wheelEvent(QWheelEvent *); -#endif - void keyPressEvent(QKeyEvent *) {} void keyReleaseEvent(QKeyEvent *); - void touchEvent(QTouchEvent *event); private: - QQuickViewInspector *inspector() const; - qreal nextZoomScale(ZoomDirection direction); - void scaleView(const qreal &factor, const QPointF &newcenter, const QPointF &oldcenter); - void zoomIn(); - void zoomOut(); - void initializeDrag(const QPointF &pos); - void dragItemToPosition(); - void moveItem(bool valid); void selectNextItem(); void selectItem(); + void showItemName(); -private slots: - void zoomTo100(); - void showSelectedItemName(); + QQuickWindowInspector *inspector() const; + GlobalInspector *globalInspector() const; -private: - bool m_originalSmooth; - bool m_dragStarted; - bool m_pinchStarted; - bool m_didPressAndHold; bool m_tapEvent; QPointer<QQuickItem> m_contentItem; - QPointF m_dragStartPosition; QPointF m_mousePosition; - QPointF m_originalPosition; - qreal m_smoothScaleFactor; - qreal m_minScale; - qreal m_maxScale; - qreal m_originalScale; ulong m_touchTimestamp; - QTimer m_pressAndHoldTimer; QTimer m_nameDisplayTimer; HoverHighlight *m_hoverHighlight; diff --git a/src/plugins/qmltooling/qmldbg_inspector/qmldbg_inspector.pro b/src/plugins/qmltooling/qmldbg_inspector/qmldbg_inspector.pro index 03446768a6..a8844944e0 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qmldbg_inspector.pro +++ b/src/plugins/qmltooling/qmldbg_inspector/qmldbg_inspector.pro @@ -1,23 +1,22 @@ TARGET = qmldbg_inspector -QT += qml-private quick-private core-private gui-private +QT += qml-private quick-private core-private gui-private packetprotocol-private INCLUDEPATH *= $$PWD $$PWD/../shared SOURCES += \ + $$PWD/globalinspector.cpp \ $$PWD/highlight.cpp \ - $$PWD/qquickviewinspector.cpp \ - $$PWD/abstracttool.cpp \ - $$PWD/abstractviewinspector.cpp \ $$PWD/inspecttool.cpp \ - $$PWD/qqmlinspectorservice.cpp + $$PWD/qqmlinspectorservice.cpp \ + $$PWD/qquickwindowinspector.cpp HEADERS += \ + $$PWD/../shared/qqmldebugpacket.h \ + $$PWD/globalinspector.h \ $$PWD/highlight.h \ - $$PWD/qquickviewinspector.h \ + $$PWD/inspecttool.h\ $$PWD/qqmlinspectorservicefactory.h \ - $$PWD/abstracttool.h \ - $$PWD/abstractviewinspector.h \ - $$PWD/inspecttool.h + $$PWD/qquickwindowinspector.h OTHER_FILES += \ qqmlinspectorservice.json diff --git a/src/plugins/qmltooling/qmldbg_inspector/qqmlinspectorservice.cpp b/src/plugins/qmltooling/qmldbg_inspector/qqmlinspectorservice.cpp index 1707091df3..48a3f656b0 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qqmlinspectorservice.cpp +++ b/src/plugins/qmltooling/qmldbg_inspector/qqmlinspectorservice.cpp @@ -1,120 +1,135 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qqmlinspectorservicefactory.h" -#include "qquickviewinspector.h" +#include "globalinspector.h" +#include "qquickwindowinspector.h" -#include <private/qqmlglobal_p.h> - -#include <QtCore/QCoreApplication> -#include <QtCore/QDebug> -#include <QtCore/QDir> -#include <QtCore/QPluginLoader> +#include <QtGui/QWindow> QT_BEGIN_NAMESPACE class QQmlInspectorServiceImpl : public QQmlInspectorService { Q_OBJECT - public: QQmlInspectorServiceImpl(QObject *parent = 0); - void addView(QObject *); - void removeView(QObject *); + void addWindow(QQuickWindow *window) Q_DECL_OVERRIDE; + void setParentWindow(QQuickWindow *window, QWindow *parent) Q_DECL_OVERRIDE; + void removeWindow(QQuickWindow *window) Q_DECL_OVERRIDE; protected: - virtual void stateChanged(State state); - virtual void messageReceived(const QByteArray &); + virtual void messageReceived(const QByteArray &) Q_DECL_OVERRIDE; -private Q_SLOTS: - void processMessage(const QByteArray &message); - void updateState(); +private slots: + void messageFromClient(const QByteArray &message); private: friend class QQmlInspectorServiceFactory; - QList<QObject*> m_views; - QmlJSDebugger::AbstractViewInspector *m_currentInspector; + QmlJSDebugger::GlobalInspector *checkInspector(); + QmlJSDebugger::GlobalInspector *m_globalInspector; + QHash<QQuickWindow *, QWindow *> m_waitingWindows; }; QQmlInspectorServiceImpl::QQmlInspectorServiceImpl(QObject *parent): - QQmlInspectorService(1, parent), m_currentInspector(0) + QQmlInspectorService(1, parent), m_globalInspector(0) { } -void QQmlInspectorServiceImpl::addView(QObject *view) +QmlJSDebugger::GlobalInspector *QQmlInspectorServiceImpl::checkInspector() { - m_views.append(view); - updateState(); + if (state() == Enabled) { + if (!m_globalInspector) { + m_globalInspector = new QmlJSDebugger::GlobalInspector(this); + connect(m_globalInspector, &QmlJSDebugger::GlobalInspector::messageToClient, + this, &QQmlDebugService::messageToClient); + for (QHash<QQuickWindow *, QWindow *>::ConstIterator i = m_waitingWindows.constBegin(); + i != m_waitingWindows.constEnd(); ++i) { + m_globalInspector->addWindow(i.key()); + if (i.value() != 0) + m_globalInspector->setParentWindow(i.key(), i.value()); + } + m_waitingWindows.clear(); + } + } else if (m_globalInspector) { + delete m_globalInspector; + m_globalInspector = 0; + } + return m_globalInspector; } -void QQmlInspectorServiceImpl::removeView(QObject *view) +void QQmlInspectorServiceImpl::addWindow(QQuickWindow *window) { - m_views.removeAll(view); - updateState(); + if (QmlJSDebugger::GlobalInspector *inspector = checkInspector()) + inspector->addWindow(window); + else + m_waitingWindows.insert(window, 0); } -void QQmlInspectorServiceImpl::stateChanged(State /*state*/) +void QQmlInspectorServiceImpl::removeWindow(QQuickWindow *window) { - QMetaObject::invokeMethod(this, "updateState", Qt::QueuedConnection); + if (QmlJSDebugger::GlobalInspector *inspector = checkInspector()) + inspector->removeWindow(window); + else + m_waitingWindows.remove(window); } -void QQmlInspectorServiceImpl::updateState() +void QQmlInspectorServiceImpl::setParentWindow(QQuickWindow *window, QWindow *parent) { - delete m_currentInspector; - m_currentInspector = 0; - - if (m_views.isEmpty() || state() != Enabled) - return; - - QQuickView *qtQuickView = qobject_cast<QQuickView*>(m_views.first()); - if (qtQuickView) - m_currentInspector = new QmlJSDebugger::QQuickViewInspector(this, qtQuickView, this); + if (QmlJSDebugger::GlobalInspector *inspector = checkInspector()) + inspector->setParentWindow(window, parent); else - qWarning() << "QQmlInspector: No inspector available for view '" - << m_views.first()->metaObject()->className() << "'."; + m_waitingWindows[window] = parent; } void QQmlInspectorServiceImpl::messageReceived(const QByteArray &message) { - QMetaObject::invokeMethod(this, "processMessage", Qt::QueuedConnection, Q_ARG(QByteArray, message)); + QMetaObject::invokeMethod(this, "messageFromClient", Qt::QueuedConnection, + Q_ARG(QByteArray, message)); } -void QQmlInspectorServiceImpl::processMessage(const QByteArray &message) +void QQmlInspectorServiceImpl::messageFromClient(const QByteArray &message) { - if (m_currentInspector) - m_currentInspector->handleMessage(message); + if (QmlJSDebugger::GlobalInspector *inspector = checkInspector()) + inspector->processMessage(message); } QQmlDebugService *QQmlInspectorServiceFactory::create(const QString &key) diff --git a/src/plugins/qmltooling/qmldbg_inspector/qqmlinspectorservicefactory.h b/src/plugins/qmltooling/qmldbg_inspector/qqmlinspectorservicefactory.h index 52f84a362d..09e6a01f96 100644 --- a/src/plugins/qmltooling/qmldbg_inspector/qqmlinspectorservicefactory.h +++ b/src/plugins/qmltooling/qmldbg_inspector/qqmlinspectorservicefactory.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/qmltooling/qmldbg_inspector/qquickviewinspector.cpp b/src/plugins/qmltooling/qmldbg_inspector/qquickviewinspector.cpp deleted file mode 100644 index de9d5617b5..0000000000 --- a/src/plugins/qmltooling/qmldbg_inspector/qquickviewinspector.cpp +++ /dev/null @@ -1,377 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qquickviewinspector.h" - -#include "highlight.h" -#include "inspecttool.h" - -#include <QtQml/private/qqmlengine_p.h> -#include <QtQuick/private/qquickitem_p.h> - -#include <QtQuick/QQuickView> -#include <QtQuick/QQuickItem> - -#include <cfloat> - -QT_BEGIN_NAMESPACE -namespace QmlJSDebugger { - -/* - * Collects all the items at the given position, from top to bottom. - */ -static void collectItemsAt(QQuickItem *item, const QPointF &pos, - QQuickItem *overlay, QList<QQuickItem *> &resultList) -{ - if (item == overlay) - return; - - if (item->flags() & QQuickItem::ItemClipsChildrenToShape) { - if (!QRectF(0, 0, item->width(), item->height()).contains(pos)) - return; - } - - QList<QQuickItem *> children = QQuickItemPrivate::get(item)->paintOrderChildItems(); - for (int i = children.count() - 1; i >= 0; --i) { - QQuickItem *child = children.at(i); - collectItemsAt(child, item->mapToItem(child, pos), overlay, resultList); - } - - if (!QRectF(0, 0, item->width(), item->height()).contains(pos)) - return; - - resultList.append(item); -} - -/* - * Returns the first visible item at the given position, or 0 when no such - * child exists. - */ -static QQuickItem *itemAt(QQuickItem *item, const QPointF &pos, - QQuickItem *overlay) -{ - if (item == overlay) - return 0; - - if (!item->isVisible() || item->opacity() == 0.0) - return 0; - - if (item->flags() & QQuickItem::ItemClipsChildrenToShape) { - if (!QRectF(0, 0, item->width(), item->height()).contains(pos)) - return 0; - } - - QList<QQuickItem *> children = QQuickItemPrivate::get(item)->paintOrderChildItems(); - for (int i = children.count() - 1; i >= 0; --i) { - QQuickItem *child = children.at(i); - if (QQuickItem *betterCandidate = itemAt(child, item->mapToItem(child, pos), - overlay)) - return betterCandidate; - } - - if (!(item->flags() & QQuickItem::ItemHasContents)) - return 0; - - if (!QRectF(0, 0, item->width(), item->height()).contains(pos)) - return 0; - - return item; -} - - -QQuickViewInspector::QQuickViewInspector(QQmlDebugService *service, QQuickView *view, - QObject *parent) : - AbstractViewInspector(service, parent), - m_view(view), - m_overlay(new QQuickItem), - m_inspectTool(new InspectTool(this, view)), - m_sendQmlReloadedMessage(false) -{ - // Try to make sure the overlay is always on top - m_overlay->setZ(FLT_MAX); - - if (QQuickItem *root = view->contentItem()) - m_overlay->setParentItem(root); - - view->installEventFilter(this); - appendTool(m_inspectTool); - connect(view, SIGNAL(statusChanged(QQuickView::Status)), - this, SLOT(onViewStatus(QQuickView::Status))); -} - -void QQuickViewInspector::changeCurrentObjects(const QList<QObject*> &objects) -{ - QList<QQuickItem*> items; - foreach (QObject *obj, objects) - if (QQuickItem *item = qobject_cast<QQuickItem*>(obj)) - items << item; - - syncSelectedItems(items); -} - -void QQuickViewInspector::reparentQmlObject(QObject *object, QObject *newParent) -{ - if (!newParent) - return; - - object->setParent(newParent); - QQuickItem *newParentItem = qobject_cast<QQuickItem*>(newParent); - QQuickItem *item = qobject_cast<QQuickItem*>(object); - if (newParentItem && item) - item->setParentItem(newParentItem); -} - -QWindow *getMasterWindow(QWindow *w) -{ - QWindow *p = w->parent(); - while (p) { - w = p; - p = p->parent(); - } - return w; -} - -Qt::WindowFlags QQuickViewInspector::windowFlags() const -{ - return getMasterWindow(m_view)->flags(); -} - -void QQuickViewInspector::setWindowFlags(Qt::WindowFlags flags) -{ - QWindow *w = getMasterWindow(m_view); - w->setFlags(flags); - // make flags are applied - w->setVisible(false); - w->setVisible(true); -} - -QQmlEngine *QQuickViewInspector::declarativeEngine() const -{ - return m_view->engine(); -} - -QQuickItem *QQuickViewInspector::topVisibleItemAt(const QPointF &pos) const -{ - QQuickItem *root = m_view->contentItem(); - return itemAt(root, root->mapFromScene(pos), m_overlay); -} - -QList<QQuickItem *> QQuickViewInspector::itemsAt(const QPointF &pos) const -{ - QQuickItem *root = m_view->contentItem(); - QList<QQuickItem *> resultList; - collectItemsAt(root, root->mapFromScene(pos), m_overlay, - resultList); - return resultList; -} - -QList<QQuickItem*> QQuickViewInspector::selectedItems() const -{ - QList<QQuickItem *> selection; - foreach (const QPointer<QQuickItem> &selectedItem, m_selectedItems) { - if (selectedItem) - selection << selectedItem; - } - return selection; -} - -void QQuickViewInspector::setSelectedItems(const QList<QQuickItem *> &items) -{ - if (!syncSelectedItems(items)) - return; - - QList<QObject*> objectList; - objectList.reserve(items.count()); - foreach (QQuickItem *item, items) - objectList << item; - - sendCurrentObjects(objectList); -} - -bool QQuickViewInspector::syncSelectedItems(const QList<QQuickItem *> &items) -{ - bool selectionChanged = false; - - // Disconnect and remove items that are no longer selected - foreach (const QPointer<QQuickItem> &item, m_selectedItems) { - if (!item) // Don't see how this can happen due to handling of destroyed() - continue; - if (items.contains(item)) - continue; - - selectionChanged = true; - item->disconnect(this); - m_selectedItems.removeOne(item); - delete m_highlightItems.take(item); - } - - // Connect and add newly selected items - foreach (QQuickItem *item, items) { - if (m_selectedItems.contains(item)) - continue; - - selectionChanged = true; - connect(item, SIGNAL(destroyed(QObject*)), this, SLOT(removeFromSelectedItems(QObject*))); - m_selectedItems.append(item); - SelectionHighlight *selectionHighlightItem; - selectionHighlightItem = new SelectionHighlight(titleForItem(item), item, m_overlay); - m_highlightItems.insert(item, selectionHighlightItem); - } - - return selectionChanged; -} - -void QQuickViewInspector::showSelectedItemName(QQuickItem *item, const QPointF &point) -{ - SelectionHighlight *highlightItem = m_highlightItems.value(item, 0); - if (highlightItem) - highlightItem->showName(point); -} - -void QQuickViewInspector::removeFromSelectedItems(QObject *object) -{ - if (QQuickItem *item = qobject_cast<QQuickItem*>(object)) { - if (m_selectedItems.removeOne(item)) - delete m_highlightItems.take(item); - } -} - -bool QQuickViewInspector::eventFilter(QObject *obj, QEvent *event) -{ - if (obj != m_view) - return QObject::eventFilter(obj, event); - - return AbstractViewInspector::eventFilter(obj, event); -} - -bool QQuickViewInspector::mouseMoveEvent(QMouseEvent *event) -{ - // TODO -// if (QQuickItem *item = topVisibleItemAt(event->pos())) -// m_view->setToolTip(titleForItem(item)); -// else -// m_view->setToolTip(QString()); - - return AbstractViewInspector::mouseMoveEvent(event); -} - -QString QQuickViewInspector::titleForItem(QQuickItem *item) const -{ - QString className = QLatin1String(item->metaObject()->className()); - QString objectStringId = idStringForObject(item); - - className.remove(QRegExp(QLatin1String("_QMLTYPE_\\d+"))); - className.remove(QRegExp(QLatin1String("_QML_\\d+"))); - if (className.startsWith(QLatin1String("QQuick"))) - className = className.mid(6); - - QString constructedName; - - if (!objectStringId.isEmpty()) { - constructedName = objectStringId + QLatin1String(" (") + className + QLatin1Char(')'); - } else if (!item->objectName().isEmpty()) { - constructedName = item->objectName() + QLatin1String(" (") + className + QLatin1Char(')'); - } else { - constructedName = className; - } - - return constructedName; -} - -void QQuickViewInspector::reloadQmlFile(const QHash<QString, QByteArray> &changesHash) -{ - clearComponentCache(); - - // Reset the selection since we are reloading the main qml - setSelectedItems(QList<QQuickItem *>()); - - QHash<QUrl, QByteArray> debugCache; - - foreach (const QString &str, changesHash.keys()) - debugCache.insert(QUrl(str), changesHash.value(str, QByteArray())); - - // Updating the cache in engine private such that the QML Data loader - // gets the changes from the cache. - QQmlEnginePrivate::get(declarativeEngine())->setDebugChangesCache(debugCache); - - m_sendQmlReloadedMessage = true; - // reloading the view such that the changes done for the files are - // reflected in view - view()->setSource(view()->source()); -} - -void QQuickViewInspector::setShowAppOnTop(bool appOnTop) -{ - m_appOnTop = appOnTop; - // Hack for QTCREATORBUG-6295. - // TODO: The root cause to be identified and fixed later. - QTimer::singleShot(100, this, SLOT(applyAppOnTop())); -} - -void QQuickViewInspector::onViewStatus(QQuickView::Status status) -{ - bool success = false; - switch (status) { - case QQuickView::Loading: - return; - case QQuickView::Ready: - if (view()->errors().count()) - break; - success = true; - break; - case QQuickView::Null: - case QQuickView::Error: - break; - default: - break; - } - if (m_sendQmlReloadedMessage) { - m_sendQmlReloadedMessage = false; - sendQmlFileReloaded(success); - } -} - -void QQuickViewInspector::applyAppOnTop() -{ - Qt::WindowFlags flags = windowFlags(); - if (m_appOnTop) - flags |= Qt::WindowStaysOnTopHint; - else - flags &= ~Qt::WindowStaysOnTopHint; - - setWindowFlags(flags); -} - -} // namespace QmlJSDebugger - -QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_inspector/qquickviewinspector.h b/src/plugins/qmltooling/qmldbg_inspector/qquickviewinspector.h deleted file mode 100644 index e823e5a03d..0000000000 --- a/src/plugins/qmltooling/qmldbg_inspector/qquickviewinspector.h +++ /dev/null @@ -1,109 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QQUICKVIEWINSPECTOR_H -#define QQUICKVIEWINSPECTOR_H - -#include "abstractviewinspector.h" - -#include <QtCore/QPointer> -#include <QtCore/QHash> -#include <QtQuick/QQuickView> - -QT_BEGIN_NAMESPACE -class QQuickView; -class QQuickItem; - -namespace QmlJSDebugger { - -class InspectTool; -class SelectionHighlight; - -class QQuickViewInspector : public AbstractViewInspector -{ - Q_OBJECT -public: - explicit QQuickViewInspector(QQmlDebugService *service, QQuickView *view, QObject *parent = 0); - - // AbstractViewInspector - void changeCurrentObjects(const QList<QObject*> &objects); - void reparentQmlObject(QObject *object, QObject *newParent); - Qt::WindowFlags windowFlags() const; - void setWindowFlags(Qt::WindowFlags flags); - QQmlEngine *declarativeEngine() const; - - QQuickView *view() const { return m_view; } - QQuickItem *overlay() const { return m_overlay; } - - QQuickItem *topVisibleItemAt(const QPointF &pos) const; - QList<QQuickItem *> itemsAt(const QPointF &pos) const; - - QList<QQuickItem *> selectedItems() const; - void setSelectedItems(const QList<QQuickItem*> &items); - - QString titleForItem(QQuickItem *item) const; - void showSelectedItemName(QQuickItem *item, const QPointF &point); - - void reloadQmlFile(const QHash<QString, QByteArray> &changesHash); - -protected: - bool eventFilter(QObject *obj, QEvent *event); - - bool mouseMoveEvent(QMouseEvent *); - - void setShowAppOnTop(bool appOnTop); - -private slots: - void removeFromSelectedItems(QObject *); - void onViewStatus(QQuickView::Status status); - void applyAppOnTop(); - -private: - bool syncSelectedItems(const QList<QQuickItem*> &items); - - QQuickView *m_view; - QQuickItem *m_overlay; - - InspectTool *m_inspectTool; - - QList<QPointer<QQuickItem> > m_selectedItems; - QHash<QQuickItem*, SelectionHighlight*> m_highlightItems; - bool m_sendQmlReloadedMessage; - bool m_appOnTop; -}; - -} // namespace QmlJSDebugger - -QT_END_NAMESPACE - -#endif // QQUICKVIEWINSPECTOR_H diff --git a/src/plugins/qmltooling/qmldbg_inspector/qquickwindowinspector.cpp b/src/plugins/qmltooling/qmldbg_inspector/qquickwindowinspector.cpp new file mode 100644 index 0000000000..2525500e65 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_inspector/qquickwindowinspector.cpp @@ -0,0 +1,232 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickwindowinspector.h" +#include "inspecttool.h" + +#include <private/qquickitem_p.h> + +QT_BEGIN_NAMESPACE + +namespace QmlJSDebugger { + +/* + * Returns the first visible item at the given position, or 0 when no such + * child exists. + */ +static QQuickItem *itemAt(QQuickItem *item, const QPointF &pos, + QQuickItem *overlay) +{ + if (item == overlay) + return 0; + + if (!item->isVisible() || item->opacity() == 0.0) + return 0; + + if (item->flags() & QQuickItem::ItemClipsChildrenToShape) { + if (!QRectF(0, 0, item->width(), item->height()).contains(pos)) + return 0; + } + + QList<QQuickItem *> children = QQuickItemPrivate::get(item)->paintOrderChildItems(); + for (int i = children.count() - 1; i >= 0; --i) { + QQuickItem *child = children.at(i); + if (QQuickItem *betterCandidate = itemAt(child, item->mapToItem(child, pos), + overlay)) + return betterCandidate; + } + + if (!(item->flags() & QQuickItem::ItemHasContents)) + return 0; + + if (!QRectF(0, 0, item->width(), item->height()).contains(pos)) + return 0; + + return item; +} + +/* + * Collects all the items at the given position, from top to bottom. + */ +static void collectItemsAt(QQuickItem *item, const QPointF &pos, + QQuickItem *overlay, QList<QQuickItem *> &resultList) +{ + if (item == overlay) + return; + + if (item->flags() & QQuickItem::ItemClipsChildrenToShape) { + if (!QRectF(0, 0, item->width(), item->height()).contains(pos)) + return; + } + + QList<QQuickItem *> children = QQuickItemPrivate::get(item)->paintOrderChildItems(); + for (int i = children.count() - 1; i >= 0; --i) { + QQuickItem *child = children.at(i); + collectItemsAt(child, item->mapToItem(child, pos), overlay, resultList); + } + + if (!QRectF(0, 0, item->width(), item->height()).contains(pos)) + return; + + resultList.append(item); +} + +QQuickWindowInspector::QQuickWindowInspector(QQuickWindow *quickWindow, QObject *parent) : + QObject(parent), + m_overlay(new QQuickItem), + m_window(quickWindow), + m_parentWindow(0), + m_tool(0) +{ + setParentWindow(quickWindow); + + // Try to make sure the overlay is always on top + m_overlay->setZ(FLT_MAX); + + if (QQuickItem *root = m_window->contentItem()) + m_overlay->setParentItem(root); + + m_window->installEventFilter(this); +} + +bool QQuickWindowInspector::eventFilter(QObject *obj, QEvent *event) +{ + if (!m_tool || obj != m_window) + return QObject::eventFilter(obj, event); + + switch (event->type()) { + case QEvent::Enter: + m_tool->enterEvent(event); + return true; + case QEvent::Leave: + m_tool->leaveEvent(event); + return true; + case QEvent::MouseButtonPress: + m_tool->mousePressEvent(static_cast<QMouseEvent*>(event)); + return true; + case QEvent::MouseMove: + m_tool->mouseMoveEvent(static_cast<QMouseEvent*>(event)); + return true; + case QEvent::MouseButtonRelease: + return true; + case QEvent::KeyPress: + m_tool->keyPressEvent(static_cast<QKeyEvent*>(event)); + return true; + case QEvent::KeyRelease: + return true; + case QEvent::MouseButtonDblClick: + m_tool->mouseDoubleClickEvent(static_cast<QMouseEvent*>(event)); + return true; +#ifndef QT_NO_WHEELEVENT + case QEvent::Wheel: + return true; +#endif + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + m_tool->touchEvent(static_cast<QTouchEvent*>(event)); + return true; + default: + break; + } + + return QObject::eventFilter(obj, event); +} + +void QQuickWindowInspector::setShowAppOnTop(bool appOnTop) +{ + if (!m_parentWindow) + return; + + Qt::WindowFlags flags = m_parentWindow->flags(); + Qt::WindowFlags newFlags = appOnTop ? (flags | Qt::WindowStaysOnTopHint) : + (flags & ~Qt::WindowStaysOnTopHint); + if (newFlags != flags) + m_parentWindow->setFlags(newFlags); +} + +bool QQuickWindowInspector::isEnabled() const +{ + return m_tool != 0; +} + +void QQuickWindowInspector::setEnabled(bool enabled) +{ + if (enabled) { + m_tool = new InspectTool(this, m_window); + } else { + delete m_tool; + m_tool = 0; + } +} + +QQuickWindow *QQuickWindowInspector::quickWindow() const +{ + return m_window; +} + +void QQuickWindowInspector::setParentWindow(QWindow *parentWindow) +{ + if (parentWindow) { + while (QWindow *w = parentWindow->parent()) + parentWindow = w; + } + + m_parentWindow = parentWindow; +} + +QList<QQuickItem *> QQuickWindowInspector::itemsAt(const QPointF &pos) const +{ + QList<QQuickItem *> resultList; + QQuickItem *root = m_window->contentItem(); + collectItemsAt(root, root->mapFromScene(pos), m_overlay, + resultList); + return resultList; +} + +QQuickItem *QQuickWindowInspector::topVisibleItemAt(const QPointF &pos) const +{ + QQuickItem *root = m_window->contentItem(); + return itemAt(root, root->mapFromScene(pos), m_overlay); +} + + +} // namespace QmlJSDebugger + +QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_inspector/qquickwindowinspector.h b/src/plugins/qmltooling/qmldbg_inspector/qquickwindowinspector.h new file mode 100644 index 0000000000..b37a9face1 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_inspector/qquickwindowinspector.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKWINDOWINSPECTOR_H +#define QQUICKWINDOWINSPECTOR_H + +#include <QtCore/QObject> + +QT_BEGIN_NAMESPACE + +class QQmlDebugService; +class QQuickWindow; +class QQmlEngine; +class QWindow; +class QQuickItem; + +namespace QmlJSDebugger { + +class InspectTool; +class GlobalInspector; + +/* + * The common code between QQuickView and QQuickView inspectors lives here, + */ +class QQuickWindowInspector : public QObject +{ + Q_OBJECT + +public: + explicit QQuickWindowInspector(QQuickWindow *quickWindow, QObject *parent = 0); + + QQuickItem *overlay() const { return m_overlay; } + QQuickItem *topVisibleItemAt(const QPointF &pos) const; + QList<QQuickItem *> itemsAt(const QPointF &pos) const; + + QQuickWindow *quickWindow() const; + + void setParentWindow(QWindow *parentWindow); + void setShowAppOnTop(bool appOnTop); + + bool isEnabled() const; + void setEnabled(bool enabled); + +protected: + bool eventFilter(QObject *, QEvent *); + +private: + QQuickItem *m_overlay; + QQuickWindow *m_window; + QWindow *m_parentWindow; + InspectTool *m_tool; +}; + +} // namespace QmlJSDebugger + +QT_END_NAMESPACE + +#endif // QQUICKWINDOWINSPECTOR_H diff --git a/src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.cpp b/src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.cpp index 057bf9523e..01c24f2395 100644 --- a/src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.cpp +++ b/src/plugins/qmltooling/qmldbg_local/qlocalclientconnection.cpp @@ -1,38 +1,43 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qlocalclientconnectionfactory.h" -#include "qpacketprotocol.h" #include "qqmldebugserver.h" #include <QtCore/qplugin.h> diff --git a/src/plugins/qmltooling/qmldbg_local/qlocalclientconnectionfactory.h b/src/plugins/qmltooling/qmldbg_local/qlocalclientconnectionfactory.h index 110e0c2395..b884a1ec23 100644 --- a/src/plugins/qmltooling/qmldbg_local/qlocalclientconnectionfactory.h +++ b/src/plugins/qmltooling/qmldbg_local/qlocalclientconnectionfactory.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/qmltooling/qmldbg_native/qmldbg_native.pro b/src/plugins/qmltooling/qmldbg_native/qmldbg_native.pro index 8902490aa0..e5489574be 100644 --- a/src/plugins/qmltooling/qmldbg_native/qmldbg_native.pro +++ b/src/plugins/qmltooling/qmldbg_native/qmldbg_native.pro @@ -1,9 +1,16 @@ TARGET = qmldbg_native -QT = qml-private core-private +QT = qml-private core-private packetprotocol-private + +HEADERS += \ + $$PWD/../shared/qqmldebugpacket.h \ + $$PWD/qqmlnativedebugconnector.h SOURCES += \ $$PWD/qqmlnativedebugconnector.cpp +INCLUDEPATH += $$PWD \ + $$PWD/../shared + OTHER_FILES += \ $$PWD/qqmlnativedebugconnector.json diff --git a/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.cpp b/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.cpp index 6621eafb27..3145601612 100644 --- a/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.cpp +++ b/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.cpp @@ -1,41 +1,48 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ -#include <private/qqmldebugconnector_p.h> -#include <private/qhooks_p.h> +#include "qqmlnativedebugconnector.h" +#include "qqmldebugpacket.h" -#include <qqmlengine.h> +#include <private/qhooks_p.h> +#include <QtQml/qjsengine.h> #include <QtCore/qdebug.h> #include <QtCore/qjsonarray.h> #include <QtCore/qjsondocument.h> @@ -65,7 +72,7 @@ Q_DECL_EXPORT void qt_qmlDebugConnectorOpen(); // member to some other place. Q_DECL_EXPORT void qt_qmlDebugSetStreamVersion(int version) { - QQmlDebugStream::s_dataStreamVersion = version; + QQmlNativeDebugConnector::setDataStreamVersion(version); } @@ -172,55 +179,25 @@ Q_DECL_EXPORT void qt_qmlDebugConnectorOpen() QT_BEGIN_NAMESPACE -class QQmlNativeDebugConnector : public QQmlDebugConnector -{ - Q_OBJECT - -public: - QQmlNativeDebugConnector(); - ~QQmlNativeDebugConnector(); - - bool blockingMode() const; - QQmlDebugService *service(const QString &name) const; - void addEngine(QQmlEngine *engine); - void removeEngine(QQmlEngine *engine); - bool addService(const QString &name, QQmlDebugService *service); - bool removeService(const QString &name); - bool open(const QVariantHash &configuration); - -private slots: - void sendMessage(const QString &name, const QByteArray &message); - void sendMessages(const QString &name, const QList<QByteArray> &messages); - -private: - void announceObjectAvailability(const QString &objectType, QObject *object, bool available); - - QVector<QQmlDebugService *> m_services; - bool m_blockingMode; -}; - QQmlNativeDebugConnector::QQmlNativeDebugConnector() : m_blockingMode(false) { const QString args = commandLineArguments(); - const QStringList lstjsDebugArguments = args.split(QLatin1Char(',')); + const auto lstjsDebugArguments = args.splitRef(QLatin1Char(',')); QStringList services; - QStringList::const_iterator argsItEnd = lstjsDebugArguments.cend(); - QStringList::const_iterator argsIt = lstjsDebugArguments.cbegin(); - for (; argsIt != argsItEnd; ++argsIt) { - const QString strArgument = *argsIt; + for (const QStringRef &strArgument : lstjsDebugArguments) { if (strArgument == QLatin1String("block")) { m_blockingMode = true; } else if (strArgument == QLatin1String("native")) { // Ignore. This is used to signal that this connector // should be loaded and that has already happened. } else if (strArgument.startsWith(QLatin1String("services:"))) { - services.append(strArgument.mid(9)); + services.append(strArgument.mid(9).toString()); } else if (!services.isEmpty()) { - services.append(strArgument); + services.append(strArgument.toString()); } else { qWarning("QML Debugger: Invalid argument \"%s\" detected. Ignoring the same.", - qUtf8Printable(strArgument)); + strArgument.toUtf8().constData()); } } setServices(services); @@ -250,8 +227,10 @@ QQmlDebugService *QQmlNativeDebugConnector::service(const QString &name) const return 0; } -void QQmlNativeDebugConnector::addEngine(QQmlEngine *engine) +void QQmlNativeDebugConnector::addEngine(QJSEngine *engine) { + Q_ASSERT(!m_engines.contains(engine)); + TRACE_PROTOCOL("Add engine to connector:" << engine); foreach (QQmlDebugService *service, m_services) service->engineAboutToBeAdded(engine); @@ -260,10 +239,14 @@ void QQmlNativeDebugConnector::addEngine(QQmlEngine *engine) foreach (QQmlDebugService *service, m_services) service->engineAdded(engine); + + m_engines.append(engine); } -void QQmlNativeDebugConnector::removeEngine(QQmlEngine *engine) +void QQmlNativeDebugConnector::removeEngine(QJSEngine *engine) { + Q_ASSERT(m_engines.contains(engine)); + TRACE_PROTOCOL("Remove engine from connector:" << engine); foreach (QQmlDebugService *service, m_services) service->engineAboutToBeRemoved(engine); @@ -272,6 +255,13 @@ void QQmlNativeDebugConnector::removeEngine(QQmlEngine *engine) foreach (QQmlDebugService *service, m_services) service->engineRemoved(engine); + + m_engines.removeOne(engine); +} + +bool QQmlNativeDebugConnector::hasEngine(QJSEngine *engine) const +{ + return m_engines.contains(engine); } void QQmlNativeDebugConnector::announceObjectAvailability(const QString &objectType, @@ -294,9 +284,8 @@ void QQmlNativeDebugConnector::announceObjectAvailability(const QString &objectT bool QQmlNativeDebugConnector::addService(const QString &name, QQmlDebugService *service) { TRACE_PROTOCOL("Add service to connector: " << qPrintable(name) << service); - for (QVector<QQmlDebugService *>::ConstIterator i = m_services.begin(); i != m_services.end(); - ++i) { - if ((*i)->name() == name) + for (auto it = m_services.cbegin(), end = m_services.cend(); it != end; ++it) { + if ((*it)->name() == name) return false; } @@ -338,6 +327,12 @@ bool QQmlNativeDebugConnector::open(const QVariantHash &configuration) return true; } +void QQmlNativeDebugConnector::setDataStreamVersion(int version) +{ + Q_ASSERT(version <= QDataStream::Qt_DefaultCompiledVersion); + s_dataStreamVersion = version; +} + void QQmlNativeDebugConnector::sendMessage(const QString &name, const QByteArray &message) { (*responseBuffer) += name.toUtf8() + ' ' + QByteArray::number(message.size()) + ' ' + message; @@ -363,21 +358,9 @@ void QQmlNativeDebugConnector::sendMessages(const QString &name, const QList<QBy sendMessage(name, messages.at(i)); } -class QQmlNativeDebugConnectorFactory : public QQmlDebugConnectorFactory +QQmlDebugConnector *QQmlNativeDebugConnectorFactory::create(const QString &key) { - Q_OBJECT - - Q_PLUGIN_METADATA(IID QQmlDebugConnectorFactory_iid FILE "qqmlnativedebugconnector.json") - -public: - QQmlNativeDebugConnectorFactory() {} - - QQmlDebugConnector *create(const QString &key) - { - return key == QLatin1String("QQmlNativeDebugConnector") ? new QQmlNativeDebugConnector : 0; - } -}; + return key == QLatin1String("QQmlNativeDebugConnector") ? new QQmlNativeDebugConnector : 0; +} QT_END_NAMESPACE - -#include "qqmlnativedebugconnector.moc" diff --git a/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.h b/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.h new file mode 100644 index 0000000000..03b5b5eb1e --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_native/qqmlnativedebugconnector.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLNATIVEDEBUGCONNECTOR_H +#define QQMLNATIVEDEBUGCONNECTOR_H + +#include <private/qqmldebugconnector_p.h> +#include <QtCore/qvector.h> + +QT_BEGIN_NAMESPACE + +class QQmlNativeDebugConnector : public QQmlDebugConnector +{ + Q_OBJECT + +public: + QQmlNativeDebugConnector(); + ~QQmlNativeDebugConnector() Q_DECL_OVERRIDE; + + bool blockingMode() const Q_DECL_OVERRIDE; + QQmlDebugService *service(const QString &name) const Q_DECL_OVERRIDE; + void addEngine(QJSEngine *engine) Q_DECL_OVERRIDE; + void removeEngine(QJSEngine *engine) Q_DECL_OVERRIDE; + bool hasEngine(QJSEngine *engine) const Q_DECL_OVERRIDE; + bool addService(const QString &name, QQmlDebugService *service) Q_DECL_OVERRIDE; + bool removeService(const QString &name) Q_DECL_OVERRIDE; + bool open(const QVariantHash &configuration) Q_DECL_OVERRIDE; + static void setDataStreamVersion(int version); + +private slots: + void sendMessage(const QString &name, const QByteArray &message); + void sendMessages(const QString &name, const QList<QByteArray> &messages); + +private: + void announceObjectAvailability(const QString &objectType, QObject *object, bool available); + + QVector<QQmlDebugService *> m_services; + QVector<QJSEngine *> m_engines; + bool m_blockingMode; +}; + +class QQmlNativeDebugConnectorFactory : public QQmlDebugConnectorFactory +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QQmlDebugConnectorFactory_iid FILE "qqmlnativedebugconnector.json") +public: + QQmlDebugConnector *create(const QString &key); +}; + +QT_END_NAMESPACE + +#endif // QQMLNATIVEDEBUGCONNECTOR_H + diff --git a/src/plugins/qmltooling/qmldbg_profiler/qmldbg_profiler.pro b/src/plugins/qmltooling/qmldbg_profiler/qmldbg_profiler.pro index 4fcfb41a8c..4629a7b81e 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qmldbg_profiler.pro +++ b/src/plugins/qmltooling/qmldbg_profiler/qmldbg_profiler.pro @@ -1,5 +1,5 @@ TARGET = qmldbg_profiler -QT = qml-private core-private +QT = qml-private core-private packetprotocol-private SOURCES += \ $$PWD/qqmlenginecontrolservice.cpp \ @@ -10,6 +10,7 @@ SOURCES += \ HEADERS += \ $$PWD/../shared/qqmlconfigurabledebugservice.h \ + $$PWD/../shared/qqmldebugpacket.h \ $$PWD/qqmlenginecontrolservice.h \ $$PWD/qqmlprofileradapter.h \ $$PWD/qqmlprofilerservice.h \ diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlenginecontrolservice.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlenginecontrolservice.cpp index 4f131ac481..6b653d5a54 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qqmlenginecontrolservice.cpp +++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlenginecontrolservice.cpp @@ -1,56 +1,61 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qqmlenginecontrolservice.h" -#include <QQmlEngine> +#include "qqmldebugpacket.h" +#include <QJSEngine> QT_BEGIN_NAMESPACE -const QString QQmlEngineControlService::s_key = QStringLiteral("EngineControl"); - -QQmlEngineControlService::QQmlEngineControlService(QObject *parent) : - QQmlDebugService(s_key, 1, parent) +QQmlEngineControlServiceImpl::QQmlEngineControlServiceImpl(QObject *parent) : + QQmlEngineControlService(1, parent) { } -void QQmlEngineControlService::messageReceived(const QByteArray &message) +void QQmlEngineControlServiceImpl::messageReceived(const QByteArray &message) { QMutexLocker lock(&dataMutex); - QQmlDebugStream d(message); + QQmlDebugPacket d(message); int command; int engineId; d >> command >> engineId; - QQmlEngine *engine = qobject_cast<QQmlEngine *>(objectForId(engineId)); + QJSEngine *engine = qobject_cast<QJSEngine *>(objectForId(engineId)); if (command == StartWaitingEngine && startingEngines.contains(engine)) { startingEngines.removeOne(engine); emit attachedToEngine(engine); @@ -60,7 +65,7 @@ void QQmlEngineControlService::messageReceived(const QByteArray &message) } } -void QQmlEngineControlService::engineAboutToBeAdded(QQmlEngine *engine) +void QQmlEngineControlServiceImpl::engineAboutToBeAdded(QJSEngine *engine) { QMutexLocker lock(&dataMutex); if (state() == Enabled) { @@ -73,7 +78,7 @@ void QQmlEngineControlService::engineAboutToBeAdded(QQmlEngine *engine) } } -void QQmlEngineControlService::engineAboutToBeRemoved(QQmlEngine *engine) +void QQmlEngineControlServiceImpl::engineAboutToBeRemoved(QJSEngine *engine) { QMutexLocker lock(&dataMutex); if (state() == Enabled) { @@ -86,7 +91,7 @@ void QQmlEngineControlService::engineAboutToBeRemoved(QQmlEngine *engine) } } -void QQmlEngineControlService::engineAdded(QQmlEngine *engine) +void QQmlEngineControlServiceImpl::engineAdded(QJSEngine *engine) { if (state() == Enabled) { QMutexLocker lock(&dataMutex); @@ -96,7 +101,7 @@ void QQmlEngineControlService::engineAdded(QQmlEngine *engine) } } -void QQmlEngineControlService::engineRemoved(QQmlEngine *engine) +void QQmlEngineControlServiceImpl::engineRemoved(QJSEngine *engine) { if (state() == Enabled) { QMutexLocker lock(&dataMutex); @@ -106,22 +111,21 @@ void QQmlEngineControlService::engineRemoved(QQmlEngine *engine) } } -void QQmlEngineControlService::sendMessage(QQmlEngineControlService::MessageType type, QQmlEngine *engine) +void QQmlEngineControlServiceImpl::sendMessage(QQmlEngineControlServiceImpl::MessageType type, QJSEngine *engine) { - QByteArray message; - QQmlDebugStream d(&message, QIODevice::WriteOnly); - d << type << idForObject(engine); - emit messageToClient(name(), message); + QQmlDebugPacket d; + d << int(type) << idForObject(engine); + emit messageToClient(name(), d.data()); } -void QQmlEngineControlService::stateChanged(State) +void QQmlEngineControlServiceImpl::stateChanged(State) { // We flush everything for any kind of state change, to avoid complicated timing issues. QMutexLocker lock(&dataMutex); - foreach (QQmlEngine *engine, startingEngines) + foreach (QJSEngine *engine, startingEngines) emit attachedToEngine(engine); startingEngines.clear(); - foreach (QQmlEngine *engine, stoppingEngines) + foreach (QJSEngine *engine, stoppingEngines) emit detachedFromEngine(engine); stoppingEngines.clear(); } diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlenginecontrolservice.h b/src/plugins/qmltooling/qmldbg_profiler/qqmlenginecontrolservice.h index e2a93e562a..1138310820 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qqmlenginecontrolservice.h +++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlenginecontrolservice.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -35,7 +41,7 @@ #define QQMLENGINECONTROLSERVICE_H #include <QMutex> -#include <private/qqmldebugservice_p.h> +#include <private/qqmldebugserviceinterfaces_p.h> // // W A R N I N G @@ -50,11 +56,9 @@ QT_BEGIN_NAMESPACE -class QQmlEngineControlService : public QQmlDebugService +class QQmlEngineControlServiceImpl : public QQmlEngineControlService { public: - static const QString s_key; - enum MessageType { EngineAboutToBeAdded, EngineAdded, @@ -67,22 +71,24 @@ public: StopWaitingEngine }; - QQmlEngineControlService(QObject *parent = 0); + QQmlEngineControlServiceImpl(QObject *parent = 0); protected: + friend class QQmlProfilerServiceFactory; + QMutex dataMutex; - QList<QQmlEngine *> startingEngines; - QList<QQmlEngine *> stoppingEngines; + QList<QJSEngine *> startingEngines; + QList<QJSEngine *> stoppingEngines; - void messageReceived(const QByteArray &); - void engineAboutToBeAdded(QQmlEngine *); - void engineAboutToBeRemoved(QQmlEngine *); - void engineAdded(QQmlEngine *); - void engineRemoved(QQmlEngine *); + void messageReceived(const QByteArray &) Q_DECL_OVERRIDE; + void engineAboutToBeAdded(QJSEngine *) Q_DECL_OVERRIDE; + void engineAboutToBeRemoved(QJSEngine *) Q_DECL_OVERRIDE; + void engineAdded(QJSEngine *) Q_DECL_OVERRIDE; + void engineRemoved(QJSEngine *) Q_DECL_OVERRIDE; - void sendMessage(MessageType type, QQmlEngine *engine); + void sendMessage(MessageType type, QJSEngine *engine); - void stateChanged(State); + void stateChanged(State) Q_DECL_OVERRIDE; }; QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp index 245900abae..a193ddea0b 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp +++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.cpp @@ -1,44 +1,53 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "qqmlprofileradapter.h" +#include "qqmldebugpacket.h" + #include <private/qqmldebugserviceinterfaces_p.h> QT_BEGIN_NAMESPACE QQmlProfilerAdapter::QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEnginePrivate *engine) : - QQmlAbstractProfilerAdapter(service), next(0) + next(0) { + setService(service); engine->enableProfiler(); connect(this, SIGNAL(profilingEnabled(quint64)), engine->profiler, SLOT(startProfiling(quint64))); connect(this, SIGNAL(profilingEnabledWhileWaiting(quint64)), @@ -49,74 +58,81 @@ QQmlProfilerAdapter::QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEngin connect(this, SIGNAL(dataRequested()), engine->profiler, SLOT(reportData())); connect(this, SIGNAL(referenceTimeKnown(QElapsedTimer)), engine->profiler, SLOT(setTimer(QElapsedTimer))); - connect(engine->profiler, SIGNAL(dataReady(QVector<QQmlProfilerData>)), - this, SLOT(receiveData(QVector<QQmlProfilerData>))); + connect(engine->profiler, + SIGNAL(dataReady(QVector<QQmlProfilerData>,QQmlProfiler::LocationHash)), + this, + SLOT(receiveData(QVector<QQmlProfilerData>,QQmlProfiler::LocationHash))); } // convert to QByteArrays that can be sent to the debug client // use of QDataStream can skew results // (see tst_qqmldebugtrace::trace() benchmark) -static void qQmlProfilerDataToByteArrays(const QQmlProfilerData *d, QList<QByteArray> &messages) +static void qQmlProfilerDataToByteArrays(const QQmlProfilerData &d, + const QQmlProfiler::LocationHash &locations, + QList<QByteArray> &messages) { - QByteArray data; - Q_ASSERT_X(((d->messageType | d->detailType) & (1 << 31)) == 0, Q_FUNC_INFO, - "You can use at most 31 message types and 31 detail types."); - for (uint decodedMessageType = 0; (d->messageType >> decodedMessageType) != 0; + QQmlDebugPacket ds; + Q_ASSERT_X((d.messageType & (1 << 31)) == 0, Q_FUNC_INFO, + "You can use at most 31 message types."); + for (quint32 decodedMessageType = 0; (d.messageType >> decodedMessageType) != 0; ++decodedMessageType) { - if ((d->messageType & (1 << decodedMessageType)) == 0) + if ((d.messageType & (1 << decodedMessageType)) == 0) continue; - for (uint decodedDetailType = 0; (d->detailType >> decodedDetailType) != 0; - ++decodedDetailType) { - if ((d->detailType & (1 << decodedDetailType)) == 0) - continue; + //### using QDataStream is relatively expensive + ds << d.time << decodedMessageType << static_cast<quint32>(d.detailType); - //### using QDataStream is relatively expensive - QQmlDebugStream ds(&data, QIODevice::WriteOnly); - ds << d->time << decodedMessageType << decodedDetailType; + QQmlProfiler::Location l = locations.value(d.locationId); - switch (decodedMessageType) { - case QQmlProfilerDefinitions::RangeStart: - if (decodedDetailType == (int)QQmlProfilerDefinitions::Binding) - ds << QQmlProfilerDefinitions::QmlBinding; - break; - case QQmlProfilerDefinitions::RangeData: - ds << (d->detailString.isEmpty() ? d->detailUrl.toString() : d->detailString); - break; - case QQmlProfilerDefinitions::RangeLocation: - ds << (d->detailUrl.isEmpty() ? d->detailString : d->detailUrl.toString()) << d->x - << d->y; - break; - case QQmlProfilerDefinitions::RangeEnd: break; - default: - Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid message type."); - break; - } - messages << data; - data.clear(); + switch (decodedMessageType) { + case QQmlProfilerDefinitions::RangeStart: + case QQmlProfilerDefinitions::RangeEnd: + break; + case QQmlProfilerDefinitions::RangeData: + ds << (l.location.sourceFile.isEmpty() ? l.url.toString() : l.location.sourceFile); + break; + case QQmlProfilerDefinitions::RangeLocation: + ds << (l.url.isEmpty() ? l.location.sourceFile : l.url.toString()) + << static_cast<qint32>(l.location.line) << static_cast<qint32>(l.location.column); + break; + default: + Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid message type."); + break; } + messages.append(ds.squeezedData()); + ds.clear(); } } qint64 QQmlProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages) { while (next != data.length()) { - if (data[next].time > until) - return data[next].time; - qQmlProfilerDataToByteArrays(&(data[next++]), messages); + const QQmlProfilerData &nextData = data.at(next); + if (nextData.time > until || messages.length() > s_numMessagesPerBatch) + return nextData.time; + qQmlProfilerDataToByteArrays(nextData, locations, messages); + ++next; } next = 0; data.clear(); + locations.clear(); return -1; } -void QQmlProfilerAdapter::receiveData(const QVector<QQmlProfilerData> &new_data) +void QQmlProfilerAdapter::receiveData(const QVector<QQmlProfilerData> &new_data, + const QQmlProfiler::LocationHash &new_locations) { if (data.isEmpty()) data = new_data; else data.append(new_data); + + if (locations.isEmpty()) + locations = new_locations; + else + locations.unite(new_locations); + service->dataReady(this); } diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h index eceb58ce3a..7e13b6c479 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h +++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofileradapter.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -54,13 +60,15 @@ class QQmlProfilerAdapter : public QQmlAbstractProfilerAdapter { Q_OBJECT public: QQmlProfilerAdapter(QQmlProfilerService *service, QQmlEnginePrivate *engine); - qint64 sendMessages(qint64 until, QList<QByteArray> &messages); + qint64 sendMessages(qint64 until, QList<QByteArray> &messages) Q_DECL_OVERRIDE; public slots: - void receiveData(const QVector<QQmlProfilerData> &new_data); + void receiveData(const QVector<QQmlProfilerData> &new_data, + const QQmlProfiler::LocationHash &locations); private: QVector<QQmlProfilerData> data; + QQmlProfiler::LocationHash locations; int next; }; diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp index a5ee494ced..e17722bb3d 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp +++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.cpp @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -35,9 +41,11 @@ #include "qv4profileradapter.h" #include "qqmlprofileradapter.h" #include "qqmlprofilerservicefactory.h" -#include <private/qqmlengine_p.h> +#include "qqmldebugpacket.h" + +#include <private/qjsengine_p.h> +#include <private/qqmldebugpluginmanager_p.h> -#include <QtCore/qdatastream.h> #include <QtCore/qurl.h> #include <QtCore/qtimer.h> #include <QtCore/qthread.h> @@ -45,11 +53,19 @@ QT_BEGIN_NAMESPACE +Q_QML_DEBUG_PLUGIN_LOADER(QQmlAbstractProfilerAdapter) + QQmlProfilerServiceImpl::QQmlProfilerServiceImpl(QObject *parent) : QQmlConfigurableDebugService<QQmlProfilerService>(1, parent), m_waitingForStop(false) { m_timer.start(); + QQmlAbstractProfilerAdapter *quickAdapter = + loadQQmlAbstractProfilerAdapter(QLatin1String("QQuickProfilerAdapter")); + if (quickAdapter) { + addGlobalProfiler(quickAdapter); + quickAdapter->setService(this); + } } QQmlProfilerServiceImpl::~QQmlProfilerServiceImpl() @@ -75,8 +91,8 @@ void QQmlProfilerServiceImpl::dataReady(QQmlAbstractProfilerAdapter *profiler) } m_startTimes.insert(0, profiler); if (dataComplete) { - QList<QQmlEngine *> enginesToRelease; - foreach (QQmlEngine *engine, m_stoppingEngines) { + QList<QJSEngine *> enginesToRelease; + foreach (QJSEngine *engine, m_stoppingEngines) { foreach (QQmlAbstractProfilerAdapter *engineProfiler, m_engineProfilers.values(engine)) { if (m_startTimes.values().contains(engineProfiler)) { enginesToRelease.append(engine); @@ -85,27 +101,30 @@ void QQmlProfilerServiceImpl::dataReady(QQmlAbstractProfilerAdapter *profiler) } } sendMessages(); - foreach (QQmlEngine *engine, enginesToRelease) { + foreach (QJSEngine *engine, enginesToRelease) { m_stoppingEngines.removeOne(engine); emit detachedFromEngine(engine); } } } -void QQmlProfilerServiceImpl::engineAboutToBeAdded(QQmlEngine *engine) +void QQmlProfilerServiceImpl::engineAboutToBeAdded(QJSEngine *engine) { Q_ASSERT_X(QThread::currentThread() == engine->thread(), Q_FUNC_INFO, "QML profilers have to be added from the engine thread"); QMutexLocker lock(&m_configMutex); - QQmlProfilerAdapter *qmlAdapter = new QQmlProfilerAdapter(this, QQmlEnginePrivate::get(engine)); + if (QQmlEngine *qmlEngine = qobject_cast<QQmlEngine *>(engine)) { + QQmlProfilerAdapter *qmlAdapter = + new QQmlProfilerAdapter(this, QQmlEnginePrivate::get(qmlEngine)); + addEngineProfiler(qmlAdapter, engine); + } QV4ProfilerAdapter *v4Adapter = new QV4ProfilerAdapter(this, QV8Engine::getV4(engine->handle())); - addEngineProfiler(qmlAdapter, engine); addEngineProfiler(v4Adapter, engine); QQmlConfigurableDebugService<QQmlProfilerService>::engineAboutToBeAdded(engine); } -void QQmlProfilerServiceImpl::engineAdded(QQmlEngine *engine) +void QQmlProfilerServiceImpl::engineAdded(QJSEngine *engine) { Q_ASSERT_X(QThread::currentThread() == engine->thread(), Q_FUNC_INFO, "QML profilers have to be added from the engine thread"); @@ -115,7 +134,7 @@ void QQmlProfilerServiceImpl::engineAdded(QQmlEngine *engine) profiler->stopWaiting(); } -void QQmlProfilerServiceImpl::engineAboutToBeRemoved(QQmlEngine *engine) +void QQmlProfilerServiceImpl::engineAboutToBeRemoved(QJSEngine *engine) { Q_ASSERT_X(QThread::currentThread() == engine->thread(), Q_FUNC_INFO, "QML profilers have to be removed from the engine thread"); @@ -135,7 +154,7 @@ void QQmlProfilerServiceImpl::engineAboutToBeRemoved(QQmlEngine *engine) } } -void QQmlProfilerServiceImpl::engineRemoved(QQmlEngine *engine) +void QQmlProfilerServiceImpl::engineRemoved(QJSEngine *engine) { Q_ASSERT_X(QThread::currentThread() == engine->thread(), Q_FUNC_INFO, "QML profilers have to be removed from the engine thread"); @@ -148,7 +167,7 @@ void QQmlProfilerServiceImpl::engineRemoved(QQmlEngine *engine) m_engineProfilers.remove(engine); } -void QQmlProfilerServiceImpl::addEngineProfiler(QQmlAbstractProfilerAdapter *profiler, QQmlEngine *engine) +void QQmlProfilerServiceImpl::addEngineProfiler(QQmlAbstractProfilerAdapter *profiler, QJSEngine *engine) { profiler->moveToThread(thread()); profiler->synchronize(m_timer); @@ -176,7 +195,6 @@ void QQmlProfilerServiceImpl::removeGlobalProfiler(QQmlAbstractProfilerAdapter * QMutexLocker lock(&m_configMutex); removeProfilerFromStartTimes(profiler); m_globalProfilers.removeOne(profiler); - delete profiler; } void QQmlProfilerServiceImpl::removeProfilerFromStartTimes(const QQmlAbstractProfilerAdapter *profiler) @@ -198,12 +216,17 @@ void QQmlProfilerServiceImpl::removeProfilerFromStartTimes(const QQmlAbstractPro * * If any engine profiler is started like that also start all global profilers. */ -void QQmlProfilerServiceImpl::startProfiling(QQmlEngine *engine, quint64 features) +void QQmlProfilerServiceImpl::startProfiling(QJSEngine *engine, quint64 features) { QMutexLocker lock(&m_configMutex); - QByteArray message; - QQmlDebugStream d(&message, QIODevice::WriteOnly); + if (features & static_cast<quint64>(1) << ProfileDebugMessages) { + if (QDebugMessageService *messageService = + QQmlDebugConnector::instance()->service<QDebugMessageService>()) + messageService->synchronizeTime(m_timer); + } + + QQmlDebugPacket d; d << m_timer.nsecsElapsed() << (int)Event << (int)StartTrace; bool startedAny = false; @@ -217,8 +240,8 @@ void QQmlProfilerServiceImpl::startProfiling(QQmlEngine *engine, quint64 feature if (startedAny) d << idForObject(engine); } else { - QSet<QQmlEngine *> engines; - for (QMultiHash<QQmlEngine *, QQmlAbstractProfilerAdapter *>::iterator i(m_engineProfilers.begin()); + QSet<QJSEngine *> engines; + for (QMultiHash<QJSEngine *, QQmlAbstractProfilerAdapter *>::iterator i(m_engineProfilers.begin()); i != m_engineProfilers.end(); ++i) { if (!i.value()->isRunning()) { engines << i.key(); @@ -226,7 +249,7 @@ void QQmlProfilerServiceImpl::startProfiling(QQmlEngine *engine, quint64 feature startedAny = true; } } - foreach (QQmlEngine *profiledEngine, engines) + foreach (QJSEngine *profiledEngine, engines) d << idForObject(profiledEngine); } @@ -239,7 +262,7 @@ void QQmlProfilerServiceImpl::startProfiling(QQmlEngine *engine, quint64 feature emit startFlushTimer(); } - emit messageToClient(name(), message); + emit messageToClient(name(), d.data()); } /*! @@ -249,14 +272,14 @@ void QQmlProfilerServiceImpl::startProfiling(QQmlEngine *engine, quint64 feature * If afterwards no more engine profilers are running, also stop all global profilers. Otherwise * only make them report their data. */ -void QQmlProfilerServiceImpl::stopProfiling(QQmlEngine *engine) +void QQmlProfilerServiceImpl::stopProfiling(QJSEngine *engine) { QMutexLocker lock(&m_configMutex); QList<QQmlAbstractProfilerAdapter *> stopping; QList<QQmlAbstractProfilerAdapter *> reporting; bool stillRunning = false; - for (QMultiHash<QQmlEngine *, QQmlAbstractProfilerAdapter *>::iterator i(m_engineProfilers.begin()); + for (QMultiHash<QJSEngine *, QQmlAbstractProfilerAdapter *>::iterator i(m_engineProfilers.begin()); i != m_engineProfilers.end(); ++i) { if (i.value()->isRunning()) { if (engine == 0 || i.key() == engine) { @@ -299,15 +322,13 @@ void QQmlProfilerServiceImpl::sendMessages() { QList<QByteArray> messages; - QByteArray data; - + QQmlDebugPacket traceEnd; if (m_waitingForStop) { - QQmlDebugStream traceEnd(&data, QIODevice::WriteOnly); traceEnd << m_timer.nsecsElapsed() << (int)Event << (int)EndTrace; - QSet<QQmlEngine *> seen; + QSet<QJSEngine *> seen; foreach (QQmlAbstractProfilerAdapter *profiler, m_startTimes) { - for (QMultiHash<QQmlEngine *, QQmlAbstractProfilerAdapter *>::iterator i(m_engineProfilers.begin()); + for (QMultiHash<QJSEngine *, QQmlAbstractProfilerAdapter *>::iterator i(m_engineProfilers.begin()); i != m_engineProfilers.end(); ++i) { if (i.value() == profiler && !seen.contains(i.key())) { seen << i.key(); @@ -320,23 +341,25 @@ void QQmlProfilerServiceImpl::sendMessages() while (!m_startTimes.empty()) { QQmlAbstractProfilerAdapter *first = m_startTimes.begin().value(); m_startTimes.erase(m_startTimes.begin()); - if (!m_startTimes.empty()) { - qint64 next = first->sendMessages(m_startTimes.begin().key(), messages); - if (next != -1) - m_startTimes.insert(next, first); - } else { - first->sendMessages(std::numeric_limits<qint64>::max(), messages); + qint64 next = first->sendMessages(m_startTimes.isEmpty() ? + std::numeric_limits<qint64>::max() : + m_startTimes.begin().key(), messages); + if (next != -1) + m_startTimes.insert(next, first); + + if (messages.length() >= QQmlAbstractProfilerAdapter::s_numMessagesPerBatch) { + emit messagesToClient(name(), messages); + messages.clear(); } } if (m_waitingForStop) { //indicate completion - messages << data; - data.clear(); + messages << traceEnd.data(); - QQmlDebugStream ds(&data, QIODevice::WriteOnly); + QQmlDebugPacket ds; ds << (qint64)-1 << (int)Complete; - messages << data; + messages << ds.data(); m_waitingForStop = false; } @@ -360,8 +383,10 @@ void QQmlProfilerServiceImpl::stateAboutToBeChanged(QQmlDebugService::State newS // Stop all profiling and send the data before we get disabled. if (newState != Enabled) { - foreach (QQmlEngine *engine, m_engineProfilers.keys()) - stopProfiling(engine); + for (auto it = m_engineProfilers.keyBegin(), end = m_engineProfilers.keyEnd(); + it != end; ++it) { + stopProfiling(*it); + } } } @@ -369,8 +394,7 @@ void QQmlProfilerServiceImpl::messageReceived(const QByteArray &message) { QMutexLocker lock(&m_configMutex); - QByteArray rwData = message; - QQmlDebugStream stream(&rwData, QIODevice::ReadOnly); + QQmlDebugPacket stream(message); int engineId = -1; quint64 features = std::numeric_limits<quint64>::max(); @@ -397,9 +421,9 @@ void QQmlProfilerServiceImpl::messageReceived(const QByteArray &message) // If engineId == -1 objectForId() and then the cast will return 0. if (enabled) - startProfiling(qobject_cast<QQmlEngine *>(objectForId(engineId)), features); + startProfiling(qobject_cast<QJSEngine *>(objectForId(engineId)), features); else - stopProfiling(qobject_cast<QQmlEngine *>(objectForId(engineId))); + stopProfiling(qobject_cast<QJSEngine *>(objectForId(engineId))); stopWaiting(); } diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.h b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.h index 9b139ffabb..6490e77f44 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.h +++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservice.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -64,8 +70,6 @@ QT_BEGIN_NAMESPACE class QUrl; -class QQmlEngine; - class QQmlProfilerServiceImpl : public QQmlConfigurableDebugService<QQmlProfilerService>, @@ -74,21 +78,22 @@ class QQmlProfilerServiceImpl : Q_OBJECT public: - void engineAboutToBeAdded(QQmlEngine *engine); - void engineAboutToBeRemoved(QQmlEngine *engine); - void engineAdded(QQmlEngine *engine); - void engineRemoved(QQmlEngine *engine); + void engineAboutToBeAdded(QJSEngine *engine) Q_DECL_OVERRIDE; + void engineAboutToBeRemoved(QJSEngine *engine) Q_DECL_OVERRIDE; + void engineAdded(QJSEngine *engine) Q_DECL_OVERRIDE; + void engineRemoved(QJSEngine *engine) Q_DECL_OVERRIDE; - void addGlobalProfiler(QQmlAbstractProfilerAdapter *profiler); - void removeGlobalProfiler(QQmlAbstractProfilerAdapter *profiler); + void addGlobalProfiler(QQmlAbstractProfilerAdapter *profiler) Q_DECL_OVERRIDE; + void removeGlobalProfiler(QQmlAbstractProfilerAdapter *profiler) Q_DECL_OVERRIDE; - void startProfiling(QQmlEngine *engine, quint64 features = std::numeric_limits<quint64>::max()); - void stopProfiling(QQmlEngine *engine); + void startProfiling(QJSEngine *engine, + quint64 features = std::numeric_limits<quint64>::max()) Q_DECL_OVERRIDE; + void stopProfiling(QJSEngine *engine) Q_DECL_OVERRIDE; QQmlProfilerServiceImpl(QObject *parent = 0); - ~QQmlProfilerServiceImpl(); + ~QQmlProfilerServiceImpl() Q_DECL_OVERRIDE; - void dataReady(QQmlAbstractProfilerAdapter *profiler); + void dataReady(QQmlAbstractProfilerAdapter *profiler) Q_DECL_OVERRIDE; signals: void startFlushTimer(); @@ -98,14 +103,14 @@ private slots: void flush(); protected: - virtual void stateAboutToBeChanged(State state); - virtual void messageReceived(const QByteArray &); + virtual void stateAboutToBeChanged(State state) Q_DECL_OVERRIDE; + virtual void messageReceived(const QByteArray &) Q_DECL_OVERRIDE; private: friend class QQmlProfilerServiceFactory; void sendMessages(); - void addEngineProfiler(QQmlAbstractProfilerAdapter *profiler, QQmlEngine *engine); + void addEngineProfiler(QQmlAbstractProfilerAdapter *profiler, QJSEngine *engine); void removeProfilerFromStartTimes(const QQmlAbstractProfilerAdapter *profiler); QElapsedTimer m_timer; @@ -113,8 +118,8 @@ private: bool m_waitingForStop; QList<QQmlAbstractProfilerAdapter *> m_globalProfilers; - QMultiHash<QQmlEngine *, QQmlAbstractProfilerAdapter *> m_engineProfilers; - QList<QQmlEngine *> m_stoppingEngines; + QMultiHash<QJSEngine *, QQmlAbstractProfilerAdapter *> m_engineProfilers; + QList<QJSEngine *> m_stoppingEngines; QMultiMap<qint64, QQmlAbstractProfilerAdapter *> m_startTimes; }; diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservicefactory.cpp b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservicefactory.cpp index 83c2075246..19100b6e8f 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservicefactory.cpp +++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservicefactory.cpp @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -42,8 +48,8 @@ QQmlDebugService *QQmlProfilerServiceFactory::create(const QString &key) if (key == QQmlProfilerServiceImpl::s_key) return new QQmlProfilerServiceImpl(this); - if (key == QQmlEngineControlService::s_key) - return new QQmlEngineControlService(this); + if (key == QQmlEngineControlServiceImpl::s_key) + return new QQmlEngineControlServiceImpl(this); return 0; } diff --git a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservicefactory.h b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservicefactory.h index b570136e5b..772e53bde7 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservicefactory.h +++ b/src/plugins/qmltooling/qmldbg_profiler/qqmlprofilerservicefactory.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp index 24e01f4c68..68a71a5524 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp +++ b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.cpp @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -37,12 +43,17 @@ QT_BEGIN_NAMESPACE QV4ProfilerAdapter::QV4ProfilerAdapter(QQmlProfilerService *service, QV4::ExecutionEngine *engine) : - QQmlAbstractProfilerAdapter(service), dataPos(0), memoryPos(0) + m_functionCallPos(0), m_memoryPos(0) { + setService(service); engine->enableProfiler(); connect(this, SIGNAL(profilingEnabled(quint64)), - engine->profiler, SLOT(startProfiling(quint64))); + this, SLOT(forwardEnabled(quint64))); connect(this, SIGNAL(profilingEnabledWhileWaiting(quint64)), + this, SLOT(forwardEnabledWhileWaiting(quint64)), Qt::DirectConnection); + connect(this, SIGNAL(v4ProfilingEnabled(quint64)), + engine->profiler, SLOT(startProfiling(quint64))); + connect(this, SIGNAL(v4ProfilingEnabledWhileWaiting(quint64)), engine->profiler, SLOT(startProfiling(quint64)), Qt::DirectConnection); connect(this, SIGNAL(profilingDisabled()), engine->profiler, SLOT(stopProfiling())); connect(this, SIGNAL(profilingDisabledWhileWaiting()), engine->profiler, SLOT(stopProfiling()), @@ -50,38 +61,44 @@ QV4ProfilerAdapter::QV4ProfilerAdapter(QQmlProfilerService *service, QV4::Execut connect(this, SIGNAL(dataRequested()), engine->profiler, SLOT(reportData())); connect(this, SIGNAL(referenceTimeKnown(QElapsedTimer)), engine->profiler, SLOT(setTimer(QElapsedTimer))); - connect(engine->profiler, SIGNAL(dataReady(QVector<QV4::Profiling::FunctionCallProperties>, + connect(engine->profiler, SIGNAL(dataReady(QV4::Profiling::FunctionLocationHash, + QVector<QV4::Profiling::FunctionCallProperties>, QVector<QV4::Profiling::MemoryAllocationProperties>)), - this, SLOT(receiveData(QVector<QV4::Profiling::FunctionCallProperties>, + this, SLOT(receiveData(QV4::Profiling::FunctionLocationHash, + QVector<QV4::Profiling::FunctionCallProperties>, QVector<QV4::Profiling::MemoryAllocationProperties>))); } -qint64 QV4ProfilerAdapter::appendMemoryEvents(qint64 until, QList<QByteArray> &messages) +qint64 QV4ProfilerAdapter::appendMemoryEvents(qint64 until, QList<QByteArray> &messages, + QQmlDebugPacket &d) { - QByteArray message; - while (memory_data.length() > memoryPos && memory_data[memoryPos].timestamp <= until) { - QQmlDebugStream d(&message, QIODevice::WriteOnly); - QV4::Profiling::MemoryAllocationProperties &props = memory_data[memoryPos]; + // Make it const, so that we cannot accidentally detach it. + const QVector<QV4::Profiling::MemoryAllocationProperties> &memoryData = m_memoryData; + + while (memoryData.length() > m_memoryPos && memoryData[m_memoryPos].timestamp <= until) { + const QV4::Profiling::MemoryAllocationProperties &props = memoryData[m_memoryPos]; d << props.timestamp << MemoryAllocation << props.type << props.size; - ++memoryPos; - messages.append(message); + ++m_memoryPos; + messages.append(d.squeezedData()); + d.clear(); } - return memory_data.length() == memoryPos ? -1 : memory_data[memoryPos].timestamp; + return memoryData.length() == m_memoryPos ? -1 : memoryData[m_memoryPos].timestamp; } qint64 QV4ProfilerAdapter::finalizeMessages(qint64 until, QList<QByteArray> &messages, - qint64 callNext) + qint64 callNext, QQmlDebugPacket &d) { if (callNext == -1) { - data.clear(); - dataPos = 0; + m_functionLocations.clear(); + m_functionCallData.clear(); + m_functionCallPos = 0; } - qint64 memoryNext = appendMemoryEvents(until, messages); + qint64 memoryNext = appendMemoryEvents(until, messages, d); if (memoryNext == -1) { - memory_data.clear(); - memoryPos = 0; + m_memoryData.clear(); + m_memoryPos = 0; return callNext; } @@ -90,64 +107,97 @@ qint64 QV4ProfilerAdapter::finalizeMessages(qint64 until, QList<QByteArray> &mes qint64 QV4ProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages) { - QByteArray message; + QQmlDebugPacket d; + + // Make it const, so that we cannot accidentally detach it. + const QVector<QV4::Profiling::FunctionCallProperties> &functionCallData = m_functionCallData; + const QV4::Profiling::FunctionLocationHash &functionLocations = m_functionLocations; + while (true) { - while (!stack.isEmpty() && (dataPos == data.length() || - stack.top() <= data[dataPos].start)) { - if (stack.top() > until) - return finalizeMessages(until, messages, stack.top()); - - appendMemoryEvents(stack.top(), messages); - QQmlDebugStream d(&message, QIODevice::WriteOnly); - d << stack.pop() << RangeEnd << Javascript; - messages.append(message); + while (!m_stack.isEmpty() && + (m_functionCallPos == functionCallData.length() || + m_stack.top() <= functionCallData[m_functionCallPos].start)) { + if (m_stack.top() > until || messages.length() > s_numMessagesPerBatch) + return finalizeMessages(until, messages, m_stack.top(), d); + + appendMemoryEvents(m_stack.top(), messages, d); + d << m_stack.pop() << RangeEnd << Javascript; + messages.append(d.squeezedData()); + d.clear(); } - while (dataPos != data.length() && (stack.empty() || data[dataPos].start < stack.top())) { - const QV4::Profiling::FunctionCallProperties &props = data[dataPos]; - if (props.start > until) - return finalizeMessages(until, messages, props.start); - - appendMemoryEvents(props.start, messages); - - QQmlDebugStream d_start(&message, QIODevice::WriteOnly); - d_start << props.start << RangeStart << Javascript; - messages.push_back(message); - message.clear(); - QQmlDebugStream d_location(&message, QIODevice::WriteOnly); - d_location << props.start << RangeLocation << Javascript << props.file << props.line - << props.column; - messages.push_back(message); - message.clear(); - QQmlDebugStream d_data(&message, QIODevice::WriteOnly); - d_data << props.start << RangeData << Javascript << props.name; - messages.push_back(message); - message.clear(); - stack.push(props.end); - ++dataPos; + while (m_functionCallPos != functionCallData.length() && + (m_stack.empty() || functionCallData[m_functionCallPos].start < m_stack.top())) { + const QV4::Profiling::FunctionCallProperties &props = + functionCallData[m_functionCallPos]; + if (props.start > until || messages.length() > s_numMessagesPerBatch) + return finalizeMessages(until, messages, props.start, d); + + appendMemoryEvents(props.start, messages, d); + auto location = functionLocations.constFind(props.id); + Q_ASSERT(location != functionLocations.constEnd()); + + d << props.start << RangeStart << Javascript; + messages.push_back(d.squeezedData()); + d.clear(); + d << props.start << RangeLocation << Javascript << location->file << location->line + << location->column; + messages.push_back(d.squeezedData()); + d.clear(); + d << props.start << RangeData << Javascript << location->name; + messages.push_back(d.squeezedData()); + d.clear(); + m_stack.push(props.end); + ++m_functionCallPos; } - if (stack.empty() && dataPos == data.length()) - return finalizeMessages(until, messages, -1); + if (m_stack.empty() && m_functionCallPos == functionCallData.length()) + return finalizeMessages(until, messages, -1, d); } } void QV4ProfilerAdapter::receiveData( - const QVector<QV4::Profiling::FunctionCallProperties> &new_data, - const QVector<QV4::Profiling::MemoryAllocationProperties> &new_memory_data) + const QV4::Profiling::FunctionLocationHash &locations, + const QVector<QV4::Profiling::FunctionCallProperties> &functionCallData, + const QVector<QV4::Profiling::MemoryAllocationProperties> &memoryData) { // In rare cases it could be that another flush or stop event is processed while data from // the previous one is still pending. In that case we just append the data. + if (m_functionLocations.isEmpty()) + m_functionLocations = locations; + else + m_functionLocations.unite(locations); - if (data.isEmpty()) - data = new_data; + if (m_functionCallData.isEmpty()) + m_functionCallData = functionCallData; else - data.append(new_data); + m_functionCallData.append(functionCallData); - if (memory_data.isEmpty()) - memory_data = new_memory_data; + if (m_memoryData.isEmpty()) + m_memoryData = memoryData; else - memory_data.append(new_memory_data); + m_memoryData.append(memoryData); service->dataReady(this); } +quint64 QV4ProfilerAdapter::translateFeatures(quint64 qmlFeatures) +{ + quint64 v4Features = 0; + const quint64 one = 1; + if (qmlFeatures & (one << ProfileJavaScript)) + v4Features |= (one << QV4::Profiling::FeatureFunctionCall); + if (qmlFeatures & (one << ProfileMemory)) + v4Features |= (one << QV4::Profiling::FeatureMemoryAllocation); + return v4Features; +} + +void QV4ProfilerAdapter::forwardEnabled(quint64 features) +{ + emit v4ProfilingEnabled(translateFeatures(features)); +} + +void QV4ProfilerAdapter::forwardEnabledWhileWaiting(quint64 features) +{ + emit v4ProfilingEnabledWhileWaiting(translateFeatures(features)); +} + QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h index cea3da72e3..968825c346 100644 --- a/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h +++ b/src/plugins/qmltooling/qmldbg_profiler/qv4profileradapter.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -47,6 +53,7 @@ #include <private/qv4profiling_p.h> #include <private/qqmlabstractprofileradapter_p.h> +#include "qqmldebugpacket.h" #include <QStack> #include <QList> @@ -62,18 +69,31 @@ public: virtual qint64 sendMessages(qint64 until, QList<QByteArray> &messages); +signals: + void v4ProfilingEnabled(quint64 v4Features); + void v4ProfilingEnabledWhileWaiting(quint64 v4Features); + public slots: - void receiveData(const QVector<QV4::Profiling::FunctionCallProperties> &, + void receiveData(const QV4::Profiling::FunctionLocationHash &, + const QVector<QV4::Profiling::FunctionCallProperties> &, const QVector<QV4::Profiling::MemoryAllocationProperties> &); +private slots: + void forwardEnabled(quint64 features); + void forwardEnabledWhileWaiting(quint64 features); + private: - QVector<QV4::Profiling::FunctionCallProperties> data; - QVector<QV4::Profiling::MemoryAllocationProperties> memory_data; - int dataPos; - int memoryPos; - QStack<qint64> stack; - qint64 appendMemoryEvents(qint64 until, QList<QByteArray> &messages); - qint64 finalizeMessages(qint64 until, QList<QByteArray> &messages, qint64 callNext); + QV4::Profiling::FunctionLocationHash m_functionLocations; + QVector<QV4::Profiling::FunctionCallProperties> m_functionCallData; + QVector<QV4::Profiling::MemoryAllocationProperties> m_memoryData; + int m_functionCallPos; + int m_memoryPos; + QStack<qint64> m_stack; + qint64 appendMemoryEvents(qint64 until, QList<QByteArray> &messages, QQmlDebugPacket &d); + qint64 finalizeMessages(qint64 until, QList<QByteArray> &messages, qint64 callNext, + QQmlDebugPacket &d); + + static quint64 translateFeatures(quint64 qmlFeatures); }; QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_quickprofiler/qmldbg_quickprofiler.pro b/src/plugins/qmltooling/qmldbg_quickprofiler/qmldbg_quickprofiler.pro new file mode 100644 index 0000000000..6ca0a184ca --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_quickprofiler/qmldbg_quickprofiler.pro @@ -0,0 +1,20 @@ +TARGET = qmldbg_quickprofiler +QT += qml-private quick-private core-private packetprotocol-private + +PLUGIN_TYPE = qmltooling +PLUGIN_CLASS_NAME = QQuickProfilerAdapterFactory +load(qt_plugin) + +INCLUDEPATH += $$PWD/../shared + +SOURCES += \ + $$PWD/qquickprofileradapter.cpp \ + $$PWD/qquickprofileradapterfactory.cpp + +HEADERS += \ + $$PWD/qquickprofileradapter.h \ + $$PWD/qquickprofileradapterfactory.h \ + $$PWD/../shared/qqmldebugpacket.h + +OTHER_FILES += \ + qquickprofileradapter.json diff --git a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp new file mode 100644 index 0000000000..9a2afd367d --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.cpp @@ -0,0 +1,175 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickprofileradapter.h" +#include "qqmldebugpacket.h" +#include <QCoreApplication> +#include <private/qqmldebugserviceinterfaces_p.h> +#include <private/qquickprofiler_p.h> + +QT_BEGIN_NAMESPACE + +QQuickProfilerAdapter::QQuickProfilerAdapter(QObject *parent) : + QQmlAbstractProfilerAdapter(parent), next(0) +{ + QQuickProfiler::initialize(this); + + // We can always do DirectConnection here as all methods are protected by mutexes + connect(this, SIGNAL(profilingEnabled(quint64)), + QQuickProfiler::s_instance, SLOT(startProfilingImpl(quint64)), Qt::DirectConnection); + connect(this, SIGNAL(profilingEnabledWhileWaiting(quint64)), + QQuickProfiler::s_instance, SLOT(startProfilingImpl(quint64)), Qt::DirectConnection); + connect(this, SIGNAL(referenceTimeKnown(QElapsedTimer)), + QQuickProfiler::s_instance, SLOT(setTimer(QElapsedTimer)), Qt::DirectConnection); + connect(this, SIGNAL(profilingDisabled()), + QQuickProfiler::s_instance, SLOT(stopProfilingImpl()), Qt::DirectConnection); + connect(this, SIGNAL(profilingDisabledWhileWaiting()), + QQuickProfiler::s_instance, SLOT(stopProfilingImpl()), Qt::DirectConnection); + connect(this, SIGNAL(dataRequested()), + QQuickProfiler::s_instance, SLOT(reportDataImpl()), Qt::DirectConnection); + connect(QQuickProfiler::s_instance, SIGNAL(dataReady(QVector<QQuickProfilerData>)), + this, SLOT(receiveData(QVector<QQuickProfilerData>)), Qt::DirectConnection); +} + +QQuickProfilerAdapter::~QQuickProfilerAdapter() +{ + if (service) + service->removeGlobalProfiler(this); +} + +// convert to QByteArrays that can be sent to the debug client +// use of QDataStream can skew results +// (see tst_qqmldebugtrace::trace() benchmark) +static void qQuickProfilerDataToByteArrays(const QQuickProfilerData &data, + QList<QByteArray> &messages) +{ + QQmlDebugPacket ds; + Q_ASSERT_X(((data.messageType | data.detailType) & (1 << 31)) == 0, Q_FUNC_INFO, + "You can use at most 31 message types and 31 detail types."); + for (uint decodedMessageType = 0; (data.messageType >> decodedMessageType) != 0; + ++decodedMessageType) { + if ((data.messageType & (1 << decodedMessageType)) == 0) + continue; + + for (uint decodedDetailType = 0; (data.detailType >> decodedDetailType) != 0; + ++decodedDetailType) { + if ((data.detailType & (1 << decodedDetailType)) == 0) + continue; + + ds << data.time << decodedMessageType << decodedDetailType; + + switch (decodedMessageType) { + case QQuickProfiler::Event: + switch (decodedDetailType) { + case QQuickProfiler::AnimationFrame: + ds << data.framerate << data.count << data.threadId; + break; + case QQuickProfiler::Key: + case QQuickProfiler::Mouse: + ds << data.inputType << data.inputA << data.inputB; + break; + } + break; + case QQuickProfiler::PixmapCacheEvent: + ds << data.detailUrl.toString(); + switch (decodedDetailType) { + case QQuickProfiler::PixmapSizeKnown: ds << data.x << data.y; break; + case QQuickProfiler::PixmapReferenceCountChanged: ds << data.count; break; + case QQuickProfiler::PixmapCacheCountChanged: ds << data.count; break; + default: break; + } + break; + case QQuickProfiler::SceneGraphFrame: + switch (decodedDetailType) { + // RendererFrame: preprocessTime, updateTime, bindingTime, renderTime + case QQuickProfiler::SceneGraphRendererFrame: ds << data.subtime_1 << data.subtime_2 << data.subtime_3 << data.subtime_4; break; + // AdaptationLayerFrame: glyphCount (which is an integer), glyphRenderTime, glyphStoreTime + case QQuickProfiler::SceneGraphAdaptationLayerFrame: ds << data.subtime_3 << data.subtime_1 << data.subtime_2; break; + // ContextFrame: compiling material time + case QQuickProfiler::SceneGraphContextFrame: ds << data.subtime_1; break; + // RenderLoop: syncTime, renderTime, swapTime + case QQuickProfiler::SceneGraphRenderLoopFrame: ds << data.subtime_1 << data.subtime_2 << data.subtime_3; break; + // TexturePrepare: bind, convert, swizzle, upload, mipmap + case QQuickProfiler::SceneGraphTexturePrepare: ds << data.subtime_1 << data.subtime_2 << data.subtime_3 << data.subtime_4 << data.subtime_5; break; + // TextureDeletion: deletionTime + case QQuickProfiler::SceneGraphTextureDeletion: ds << data.subtime_1; break; + // PolishAndSync: polishTime, waitTime, syncTime, animationsTime, + case QQuickProfiler::SceneGraphPolishAndSync: ds << data.subtime_1 << data.subtime_2 << data.subtime_3 << data.subtime_4; break; + // WindowsRenderLoop: GL time, make current time, SceneGraph time + case QQuickProfiler::SceneGraphWindowsRenderShow: ds << data.subtime_1 << data.subtime_2 << data.subtime_3; break; + // WindowsAnimations: update time + case QQuickProfiler::SceneGraphWindowsAnimations: ds << data.subtime_1; break; + // non-threaded rendering: polish time + case QQuickProfiler::SceneGraphPolishFrame: ds << data.subtime_1; break; + default:break; + } + break; + default: + Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid message type."); + break; + } + messages.append(ds.squeezedData()); + ds.clear(); + } + } +} + +qint64 QQuickProfilerAdapter::sendMessages(qint64 until, QList<QByteArray> &messages) +{ + while (next < m_data.size()) { + if (m_data[next].time <= until && messages.length() <= s_numMessagesPerBatch) + qQuickProfilerDataToByteArrays(m_data[next++], messages); + else + return m_data[next].time; + } + m_data.clear(); + next = 0; + return -1; +} + +void QQuickProfilerAdapter::receiveData(const QVector<QQuickProfilerData> &new_data) +{ + if (m_data.isEmpty()) + m_data = new_data; + else + m_data.append(new_data); + service->dataReady(this); +} + +QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.h b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.h new file mode 100644 index 0000000000..0983561d2c --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKPROFILERADAPTER_H +#define QQUICKPROFILERADAPTER_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 <QtQml/private/qqmlabstractprofileradapter_p.h> +#include <QtQuick/private/qquickprofiler_p.h> + +QT_BEGIN_NAMESPACE + +class QQuickProfilerAdapter : public QQmlAbstractProfilerAdapter { + Q_OBJECT +public: + QQuickProfilerAdapter(QObject *parent = 0); + ~QQuickProfilerAdapter(); + qint64 sendMessages(qint64 until, QList<QByteArray> &messages); + +public slots: + void receiveData(const QVector<QQuickProfilerData> &new_data); + +private: + int next; + QVector<QQuickProfilerData> m_data; +}; + +QT_END_NAMESPACE + +#endif // QQUICKPROFILERADAPTER_H diff --git a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.json b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.json new file mode 100644 index 0000000000..76b08fbcab --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapter.json @@ -0,0 +1,3 @@ +{ + "Keys": [ "QQuickProfilerAdapter" ] +} diff --git a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapterfactory.cpp b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapterfactory.cpp new file mode 100644 index 0000000000..c85bca0ac7 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapterfactory.cpp @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickprofileradapterfactory.h" +#include "qquickprofileradapter.h" +#include <private/qqmldebugconnector_p.h> +#include <private/qqmldebugserviceinterfaces_p.h> + +QT_BEGIN_NAMESPACE + +QQmlAbstractProfilerAdapter *QQuickProfilerAdapterFactory::create(const QString &key) +{ + if (key != QLatin1String("QQuickProfilerAdapter")) + return 0; + return new QQuickProfilerAdapter(this); +} + +QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapterfactory.h b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapterfactory.h new file mode 100644 index 0000000000..489545b504 --- /dev/null +++ b/src/plugins/qmltooling/qmldbg_quickprofiler/qquickprofileradapterfactory.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKPROFILERADAPTERFACTORY_H +#define QQUICKPROFILERADAPTERFACTORY_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 <QtQml/private/qqmlabstractprofileradapter_p.h> +#include <QtQuick/private/qquickprofiler_p.h> + +QT_BEGIN_NAMESPACE + +class QQuickProfilerAdapterFactory : public QQmlAbstractProfilerAdapterFactory +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QQmlAbstractProfilerAdapterFactory_iid FILE "qquickprofileradapter.json") +public: + QQmlAbstractProfilerAdapter *create(const QString &key); +}; + +QT_END_NAMESPACE + +#endif // QQUICKPROFILERADAPTERFACTORY_H diff --git a/src/plugins/qmltooling/qmldbg_server/qmldbg_server.pro b/src/plugins/qmltooling/qmldbg_server/qmldbg_server.pro index 54fe0a4473..fffdb4c888 100644 --- a/src/plugins/qmltooling/qmldbg_server/qmldbg_server.pro +++ b/src/plugins/qmltooling/qmldbg_server/qmldbg_server.pro @@ -1,15 +1,14 @@ TARGET = qmldbg_server -QT = qml-private core-private +QT = qml-private packetprotocol-private SOURCES += \ - $$PWD/qqmldebugserver.cpp \ - $$PWD/../shared/qpacketprotocol.cpp + $$PWD/qqmldebugserver.cpp HEADERS += \ $$PWD/qqmldebugserverfactory.h \ $$PWD/../shared/qqmldebugserver.h \ - $$PWD/../shared/qpacketprotocol.h \ - $$PWD/../shared/qqmldebugserverconnection.h + $$PWD/../shared/qqmldebugserverconnection.h \ + $$PWD/../shared/qqmldebugpacket.h INCLUDEPATH += $$PWD \ $$PWD/../shared diff --git a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp b/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp index 2e895778f0..cbde86e389 100644 --- a/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp +++ b/src/plugins/qmltooling/qmldbg_server/qqmldebugserver.cpp @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -33,23 +39,23 @@ #include "qqmldebugserver.h" #include "qqmldebugserverfactory.h" -#include "qpacketprotocol.h" #include "qqmldebugserverconnection.h" +#include "qqmldebugpacket.h" #include <private/qqmldebugservice_p.h> -#include <private/qqmlengine_p.h> +#include <private/qjsengine_p.h> #include <private/qqmlglobal_p.h> #include <private/qqmldebugpluginmanager_p.h> +#include <private/qqmldebugserviceinterfaces_p.h> +#include <private/qpacketprotocol_p.h> #include <QtCore/QAtomicInt> #include <QtCore/QDir> #include <QtCore/QPluginLoader> #include <QtCore/QStringList> +#include <QtCore/QVector> #include <QtCore/qwaitcondition.h> -#include <private/qobject_p.h> -#include <private/qcoreapplication_p.h> - QT_BEGIN_NAMESPACE /* @@ -103,6 +109,11 @@ public: m_fileName = fileName; } + const QString &pluginName() const + { + return m_pluginName; + } + void run(); private: @@ -120,25 +131,26 @@ class QQmlDebugServerImpl : public QQmlDebugServer public: QQmlDebugServerImpl(); - bool blockingMode() const; + bool blockingMode() const Q_DECL_OVERRIDE; - QQmlDebugService *service(const QString &name) const; + QQmlDebugService *service(const QString &name) const Q_DECL_OVERRIDE; - void addEngine(QQmlEngine *engine); - void removeEngine(QQmlEngine *engine); + void addEngine(QJSEngine *engine) Q_DECL_OVERRIDE; + void removeEngine(QJSEngine *engine) Q_DECL_OVERRIDE; + bool hasEngine(QJSEngine *engine) const Q_DECL_OVERRIDE; - bool addService(const QString &name, QQmlDebugService *service); - bool removeService(const QString &name); + bool addService(const QString &name, QQmlDebugService *service) Q_DECL_OVERRIDE; + bool removeService(const QString &name) Q_DECL_OVERRIDE; - bool open(const QVariantHash &configuration); - void setDevice(QIODevice *socket); + bool open(const QVariantHash &configuration) Q_DECL_OVERRIDE; + void setDevice(QIODevice *socket) Q_DECL_OVERRIDE; void parseArguments(); static void cleanup(); private slots: - void wakeEngine(QQmlEngine *engine); + void wakeEngine(QJSEngine *engine); void sendMessage(const QString &name, const QByteArray &message); void sendMessages(const QString &name, const QList<QByteArray> &messages); void changeServiceState(const QString &serviceName, QQmlDebugService::State state); @@ -155,6 +167,7 @@ private: EngineCondition() : numServices(0), condition(new QWaitCondition) {} bool waitForServices(QMutex *locked, int numEngines); + bool isWaiting() const { return numServices > 0; } void wake(); private: @@ -172,10 +185,11 @@ private: QStringList m_clientPlugins; bool m_gotHello; bool m_blockingMode; + bool m_clientSupportsMultiPackets; - QHash<QQmlEngine *, EngineCondition> m_engineConditions; + QHash<QJSEngine *, EngineCondition> m_engineConditions; - QMutex m_helloMutex; + mutable QMutex m_helloMutex; QWaitCondition m_helloCondition; QQmlDebugServerThread m_thread; QPacketProtocol *m_protocol; @@ -260,7 +274,8 @@ static void cleanupOnShutdown() QQmlDebugServerImpl::QQmlDebugServerImpl() : m_connection(0), m_gotHello(false), - m_blockingMode(false) + m_blockingMode(false), + m_clientSupportsMultiPackets(false) { static bool postRoutineAdded = false; if (!postRoutineAdded) { @@ -302,6 +317,9 @@ bool QQmlDebugServerImpl::open(const QVariantHash &configuration = QVariantHash( } } + if (m_thread.pluginName().isEmpty()) + return false; + QMutexLocker locker(&m_helloMutex); m_thread.start(); m_helloCondition.wait(&m_helloMutex); // wait for connection @@ -326,41 +344,41 @@ void QQmlDebugServerImpl::parseArguments() QString fileName; QStringList services; - const QStringList lstjsDebugArguments = args.split(QLatin1Char(',')); - QStringList::const_iterator argsItEnd = lstjsDebugArguments.cend(); - QStringList::const_iterator argsIt = lstjsDebugArguments.cbegin(); - for (; argsIt != argsItEnd; ++argsIt) { - const QString strArgument = *argsIt; + const auto lstjsDebugArguments = args.splitRef(QLatin1Char(',')); + for (auto argsIt = lstjsDebugArguments.begin(), argsItEnd = lstjsDebugArguments.end(); argsIt != argsItEnd; ++argsIt) { + const QStringRef &strArgument = *argsIt; if (strArgument.startsWith(QLatin1String("port:"))) { portFrom = strArgument.mid(5).toInt(&ok); portTo = portFrom; - QStringList::const_iterator argsNext = argsIt + 1; + const auto argsNext = argsIt + 1; if (argsNext == argsItEnd) break; - const QString nextArgument = *argsNext; - - // Don't use QStringLiteral here. QRegExp has a global cache and will save an implicitly - // shared copy of the passed string. That copy isn't properly detached when the library - // is unloaded if the original string lives in the library's .rodata - if (ok && nextArgument.contains(QRegExp(QLatin1String("^\\s*\\d+\\s*$")))) { - portTo = nextArgument.toInt(&ok); - ++argsIt; + if (ok) { + const QString nextArgument = argsNext->toString(); + + // Don't use QStringLiteral here. QRegExp has a global cache and will save an implicitly + // shared copy of the passed string. That copy isn't properly detached when the library + // is unloaded if the original string lives in the library's .rodata + if (nextArgument.contains(QRegExp(QLatin1String("^\\s*\\d+\\s*$")))) { + portTo = nextArgument.toInt(&ok); + ++argsIt; + } } } else if (strArgument.startsWith(QLatin1String("host:"))) { - hostAddress = strArgument.mid(5); + hostAddress = strArgument.mid(5).toString(); } else if (strArgument == QLatin1String("block")) { block = true; } else if (strArgument.startsWith(QLatin1String("file:"))) { - fileName = strArgument.mid(5); + fileName = strArgument.mid(5).toString(); ok = !fileName.isEmpty(); } else if (strArgument.startsWith(QLatin1String("services:"))) { - services.append(strArgument.mid(9)); + services.append(strArgument.mid(9).toString()); } else if (!services.isEmpty()) { - services.append(strArgument); + services.append(strArgument.toString()); } else { - qWarning() << QString::fromLatin1("QML Debugger: Invalid argument '%1' " - "detected. Ignoring the same.") - .arg(strArgument); + const QString message = tr("QML Debugger: Invalid argument \"%1\" detected." + " Ignoring the same.").arg(strArgument.toString()); + qWarning("%s", qPrintable(message)); } } @@ -372,9 +390,45 @@ void QQmlDebugServerImpl::parseArguments() else m_thread.setPortRange(portFrom, portTo, hostAddress); } else { - qWarning() << QString::fromLatin1("QML Debugger: Ignoring \"-qmljsdebugger=%1\". " - "Format is qmljsdebugger=port:<port_from>[,port_to],host:" - "<ip address>][,block]").arg(args); + QString usage; + QTextStream str(&usage); + str << tr("QML Debugger: Ignoring \"-qmljsdebugger=%1\".").arg(args) << '\n' + << tr("The format is \"-qmljsdebugger=[file:<file>|port:<port_from>][,<port_to>]" + "[,host:<ip address>][,block][,services:<service>][,<service>]*\"") << '\n' + << tr("\"file:\" can be used to specify the name of a file the debugger will try " + "to connect to using a QLocalSocket. If \"file:\" is given any \"host:\" and" + "\"port:\" arguments will be ignored.") << '\n' + << tr("\"host:\" and \"port:\" can be used to specify an address and a single " + "port or a range of ports the debugger will try to bind to with a " + "QTcpServer.") << '\n' + << tr("\"block\" makes the debugger and some services wait for clients to be " + "connected and ready before the first QML engine starts.") << '\n' + << tr("\"services:\" can be used to specify which debug services the debugger " + "should load. Some debug services interact badly with others. The V4 " + "debugger should not be loaded when using the QML profiler as it will force " + "any V4 engines to use the JavaScript interpreter rather than the JIT. The " + "following debug services are available by default:") << '\n' + << QQmlEngineDebugService::s_key << "\t- " << tr("The QML debugger") << '\n' + << QV4DebugService::s_key << "\t- " << tr("The V4 debugger") << '\n' + << QQmlInspectorService::s_key << "\t- " << tr("The QML inspector") << '\n' + << QQmlProfilerService::s_key << "\t- " << tr("The QML profiler") << '\n' + << QQmlEngineControlService::s_key << "\t- " + //: Please preserve the line breaks and formatting + << tr("Allows the client to delay the starting and stopping of\n" + "\t\t QML engines until other services are ready. QtCreator\n" + "\t\t uses this service with the QML profiler in order to\n" + "\t\t profile multiple QML engines at the same time.") + << '\n' << QDebugMessageService::s_key << "\t- " + //: Please preserve the line breaks and formatting + << tr("Sends qDebug() and similar messages over the QML debug\n" + "\t\t connection. QtCreator uses this for showing debug\n" + "\t\t messages in the debugger console.") << '\n' + << tr("Other services offered by qmltooling plugins that implement " + "QQmlDebugServiceFactory and which can be found in the standard plugin " + "paths will also be available and can be specified. If no \"services\" " + "argument is given, all services found this way, including the default " + "ones, are loaded."); + qWarning("%s", qPrintable(usage)); } } @@ -388,7 +442,7 @@ void QQmlDebugServerImpl::receiveMessage() if (!m_protocol) return; - QQmlDebugStream in(m_protocol->read().data()); + QQmlDebugPacket in(m_protocol->read()); QString name; @@ -402,16 +456,20 @@ void QQmlDebugServerImpl::receiveMessage() //Get the supported QDataStream version if (!in.atEnd()) { - in >> QQmlDebugStream::s_dataStreamVersion; - if (QQmlDebugStream::s_dataStreamVersion > QDataStream().version()) - QQmlDebugStream::s_dataStreamVersion = QDataStream().version(); + in >> s_dataStreamVersion; + if (s_dataStreamVersion > QDataStream::Qt_DefaultCompiledVersion) + s_dataStreamVersion = QDataStream::Qt_DefaultCompiledVersion; } + if (!in.atEnd()) + in >> m_clientSupportsMultiPackets; + else + m_clientSupportsMultiPackets = false; + // Send the hello answer immediately, since it needs to arrive before // the plugins below start sending messages. - QByteArray helloAnswer; - QQmlDebugStream out(&helloAnswer, QIODevice::WriteOnly); + QQmlDebugPacket out; QStringList pluginNames; QList<float> pluginVersions; const int count = m_plugins.count(); @@ -424,11 +482,9 @@ void QQmlDebugServerImpl::receiveMessage() } out << QString(QStringLiteral("QDeclarativeDebugClient")) << 0 << protocolVersion - << pluginNames << pluginVersions << QQmlDebugStream::s_dataStreamVersion; + << pluginNames << pluginVersions << dataStreamVersion(); - QPacket pack; - pack.writeRawData(helloAnswer.data(), helloAnswer.length()); - m_protocol->send(pack); + m_protocol->send(out.data()); m_connection->flush(); QMutexLocker helloLock(&m_helloMutex); @@ -470,14 +526,16 @@ void QQmlDebugServerImpl::receiveMessage() } else { if (m_gotHello) { - QByteArray message; - in >> message; - QHash<QString, QQmlDebugService *>::Iterator iter = m_plugins.find(name); if (iter == m_plugins.end()) { qWarning() << "QML Debugger: Message received for missing plugin" << name << '.'; } else { - (*iter)->messageReceived(message); + QQmlDebugService *service = *iter; + QByteArray message; + while (!in.atEnd()) { + in >> message; + service->messageReceived(message); + } } } else { qWarning("QML Debugger: Invalid hello message."); @@ -521,12 +579,14 @@ QQmlDebugService *QQmlDebugServerImpl::service(const QString &name) const return m_plugins.value(name); } -void QQmlDebugServerImpl::addEngine(QQmlEngine *engine) +void QQmlDebugServerImpl::addEngine(QJSEngine *engine) { // to be executed outside of debugger thread Q_ASSERT(QThread::currentThread() != &m_thread); QMutexLocker locker(&m_helloMutex); + Q_ASSERT(!m_engineConditions.contains(engine)); + foreach (QQmlDebugService *service, m_plugins) service->engineAboutToBeAdded(engine); @@ -536,12 +596,14 @@ void QQmlDebugServerImpl::addEngine(QQmlEngine *engine) service->engineAdded(engine); } -void QQmlDebugServerImpl::removeEngine(QQmlEngine *engine) +void QQmlDebugServerImpl::removeEngine(QJSEngine *engine) { // to be executed outside of debugger thread Q_ASSERT(QThread::currentThread() != &m_thread); QMutexLocker locker(&m_helloMutex); + Q_ASSERT(m_engineConditions.contains(engine)); + foreach (QQmlDebugService *service, m_plugins) service->engineAboutToBeRemoved(engine); @@ -549,6 +611,16 @@ void QQmlDebugServerImpl::removeEngine(QQmlEngine *engine) foreach (QQmlDebugService *service, m_plugins) service->engineRemoved(engine); + + m_engineConditions.remove(engine); +} + +bool QQmlDebugServerImpl::hasEngine(QJSEngine *engine) const +{ + QMutexLocker locker(&m_helloMutex); + QHash<QJSEngine *, EngineCondition>::ConstIterator i = m_engineConditions.constFind(engine); + // if we're still waiting the engine isn't fully "there", yet, nor fully removed. + return i != m_engineConditions.constEnd() && !i.value().isWaiting(); } bool QQmlDebugServerImpl::addService(const QString &name, QQmlDebugService *service) @@ -564,10 +636,10 @@ bool QQmlDebugServerImpl::addService(const QString &name, QQmlDebugService *serv connect(service, SIGNAL(messagesToClient(QString,QList<QByteArray>)), this, SLOT(sendMessages(QString,QList<QByteArray>))); - connect(service, SIGNAL(attachedToEngine(QQmlEngine*)), - this, SLOT(wakeEngine(QQmlEngine*)), Qt::QueuedConnection); - connect(service, SIGNAL(detachedFromEngine(QQmlEngine*)), - this, SLOT(wakeEngine(QQmlEngine*)), Qt::QueuedConnection); + connect(service, SIGNAL(attachedToEngine(QJSEngine*)), + this, SLOT(wakeEngine(QJSEngine*)), Qt::QueuedConnection); + connect(service, SIGNAL(detachedFromEngine(QJSEngine*)), + this, SLOT(wakeEngine(QJSEngine*)), Qt::QueuedConnection); service->setState(QQmlDebugService::Unavailable); m_plugins.insert(name, service); @@ -587,18 +659,16 @@ bool QQmlDebugServerImpl::removeService(const QString &name) m_plugins.remove(name); service->setState(QQmlDebugService::NotConnected); - disconnect(service, SIGNAL(detachedFromEngine(QQmlEngine*)), - this, SLOT(wakeEngine(QQmlEngine*))); - disconnect(service, SIGNAL(attachedToEngine(QQmlEngine*)), - this, SLOT(wakeEngine(QQmlEngine*))); + disconnect(service, SIGNAL(detachedFromEngine(QJSEngine*)), + this, SLOT(wakeEngine(QJSEngine*))); + disconnect(service, SIGNAL(attachedToEngine(QJSEngine*)), + this, SLOT(wakeEngine(QJSEngine*))); disconnect(service, SIGNAL(messagesToClient(QString,QList<QByteArray>)), this, SLOT(sendMessages(QString,QList<QByteArray>))); disconnect(service, SIGNAL(messageToClient(QString,QByteArray)), this, SLOT(sendMessage(QString,QByteArray))); - m_plugins.remove(service->name()); - return true; } @@ -612,13 +682,9 @@ bool QQmlDebugServerImpl::canSendMessage(const QString &name) void QQmlDebugServerImpl::doSendMessage(const QString &name, const QByteArray &message) { - QByteArray prefixed; - QQmlDebugStream out(&prefixed, QIODevice::WriteOnly); + QQmlDebugPacket out; out << name << message; - - QPacket pack; - pack.writeRawData(prefixed.data(), prefixed.length()); - m_protocol->send(pack); + m_protocol->send(out.data()); } void QQmlDebugServerImpl::sendMessage(const QString &name, const QByteArray &message) @@ -632,13 +698,21 @@ void QQmlDebugServerImpl::sendMessage(const QString &name, const QByteArray &mes void QQmlDebugServerImpl::sendMessages(const QString &name, const QList<QByteArray> &messages) { if (canSendMessage(name)) { - foreach (const QByteArray &message, messages) - doSendMessage(name, message); + if (m_clientSupportsMultiPackets) { + QQmlDebugPacket out; + out << name; + foreach (const QByteArray &message, messages) + out << message; + m_protocol->send(out.data()); + } else { + foreach (const QByteArray &message, messages) + doSendMessage(name, message); + } m_connection->flush(); } } -void QQmlDebugServerImpl::wakeEngine(QQmlEngine *engine) +void QQmlDebugServerImpl::wakeEngine(QJSEngine *engine) { // to be executed in debugger thread Q_ASSERT(QThread::currentThread() == thread()); diff --git a/src/plugins/qmltooling/qmldbg_server/qqmldebugserverfactory.h b/src/plugins/qmltooling/qmldbg_server/qqmldebugserverfactory.h index 825a71bab8..fd71b03019 100644 --- a/src/plugins/qmltooling/qmldbg_server/qqmldebugserverfactory.h +++ b/src/plugins/qmltooling/qmldbg_server/qqmldebugserverfactory.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp index c8010a4aa9..3d64312b16 100644 --- a/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp +++ b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnection.cpp @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnectionfactory.h b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnectionfactory.h index 97dde03087..52d9f4b709 100644 --- a/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnectionfactory.h +++ b/src/plugins/qmltooling/qmldbg_tcp/qtcpserverconnectionfactory.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** diff --git a/src/plugins/qmltooling/qmltooling.pro b/src/plugins/qmltooling/qmltooling.pro index 263e76e016..3728126dd9 100644 --- a/src/plugins/qmltooling/qmltooling.pro +++ b/src/plugins/qmltooling/qmltooling.pro @@ -1,5 +1,9 @@ TEMPLATE = subdirs +# Utilities +SUBDIRS += \ + packetprotocol + # Connectors SUBDIRS += \ qmldbg_native \ @@ -12,4 +16,15 @@ SUBDIRS += \ qmldbg_debugger \ qmldbg_profiler -qtHaveModule(quick): SUBDIRS += qmldbg_inspector +qmldbg_server.depends = packetprotocol +qmldbg_native.depends = packetprotocol +qmldbg_debugger.depends = packetprotocol +qmldbg_profiler.depends = packetprotocol + +qtHaveModule(quick) { + SUBDIRS += \ + qmldbg_inspector \ + qmldbg_quickprofiler + qmldbg_inspector.depends = packetprotocol + qmldbg_quickprofiler.depends = packetprotocol +} diff --git a/src/plugins/qmltooling/shared/qpacketprotocol.cpp b/src/plugins/qmltooling/shared/qpacketprotocol.cpp deleted file mode 100644 index 9a58f803c1..0000000000 --- a/src/plugins/qmltooling/shared/qpacketprotocol.cpp +++ /dev/null @@ -1,531 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qpacketprotocol.h" - -#include <QtCore/QBuffer> -#include <QtCore/QElapsedTimer> -#include <private/qiodevice_p.h> - -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_UNUSED(writeBytes); - 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; -} - -/*! - 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_subtract_from_timeout(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/plugins/qmltooling/shared/qpacketprotocol.h b/src/plugins/qmltooling/shared/qpacketprotocol.h deleted file mode 100644 index c571e8d2b8..0000000000 --- a/src/plugins/qmltooling/shared/qpacketprotocol.h +++ /dev/null @@ -1,111 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL21$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. -** -** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QPACKETPROTOCOL_H -#define QPACKETPROTOCOL_H - -#include <QtCore/qobject.h> -#include <QtCore/qdatastream.h> - -QT_BEGIN_NAMESPACE - -class QIODevice; -class QBuffer; -class QPacket; -class QPacketAutoSend; -class QPacketProtocolPrivate; - -class 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 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 QPacketAutoSend : public QPacket -{ -public: - virtual ~QPacketAutoSend(); - -private: - friend class QPacketProtocol; - QPacketAutoSend(QPacketProtocol *); - QPacketProtocol *p; -}; - -QT_END_NAMESPACE - -#endif diff --git a/src/plugins/qmltooling/shared/qqmlconfigurabledebugservice.h b/src/plugins/qmltooling/shared/qqmlconfigurabledebugservice.h index 9aa4531428..85ff9b182f 100644 --- a/src/plugins/qmltooling/shared/qqmlconfigurabledebugservice.h +++ b/src/plugins/qmltooling/shared/qqmlconfigurabledebugservice.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -66,7 +72,7 @@ protected: { QMutexLocker lock(&m_configMutex); m_waitingForConfiguration = false; - foreach (QQmlEngine *engine, m_waitingEngines) + for (QJSEngine *engine : qAsConst(m_waitingEngines)) emit Base::attachedToEngine(engine); m_waitingEngines.clear(); } @@ -79,7 +85,7 @@ protected: QQmlDebugConnector::instance()->blockingMode()); } - void stateChanged(QQmlDebugService::State newState) + void stateChanged(QQmlDebugService::State newState) Q_DECL_OVERRIDE { if (newState != QQmlDebugService::Enabled) stopWaiting(); @@ -87,7 +93,7 @@ protected: init(); } - void engineAboutToBeAdded(QQmlEngine *engine) + void engineAboutToBeAdded(QJSEngine *engine) Q_DECL_OVERRIDE { QMutexLocker lock(&m_configMutex); if (m_waitingForConfiguration) @@ -97,7 +103,7 @@ protected: } QMutex m_configMutex; - QList<QQmlEngine *> m_waitingEngines; + QList<QJSEngine *> m_waitingEngines; bool m_waitingForConfiguration; }; diff --git a/src/plugins/qmltooling/shared/qqmldebugpacket.h b/src/plugins/qmltooling/shared/qqmldebugpacket.h new file mode 100644 index 0000000000..f1c21e0a2b --- /dev/null +++ b/src/plugins/qmltooling/shared/qqmldebugpacket.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLDEBUGPACKET_P_H +#define QQMLDEBUGPACKET_P_H + +#include <QtCore/qbuffer.h> +#include <QtQml/private/qqmldebugconnector_p.h> +#include <QtPacketProtocol/private/qpacket_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. +// + +QT_BEGIN_NAMESPACE + +// QPacket with a fixed data stream version, centrally set by QQmlDebugServer +class QQmlDebugPacket : public QPacket +{ +public: + QQmlDebugPacket() : QPacket(QQmlDebugConnector::dataStreamVersion()) {} + QQmlDebugPacket(const QByteArray &ba) : QPacket(QQmlDebugConnector::dataStreamVersion(), ba) {} +}; + +QT_END_NAMESPACE + +#endif // QQMLDEBUGPACKET_P_H diff --git a/src/plugins/qmltooling/shared/qqmldebugserver.h b/src/plugins/qmltooling/shared/qqmldebugserver.h index a7c17075d9..424c7c4120 100644 --- a/src/plugins/qmltooling/shared/qqmldebugserver.h +++ b/src/plugins/qmltooling/shared/qqmldebugserver.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** @@ -37,6 +43,8 @@ #include <private/qqmldebugconnector_p.h> #include <private/qtqmlglobal_p.h> +#include <QtCore/QIODevice> + // // W A R N I N G // ------------- diff --git a/src/plugins/qmltooling/shared/qqmldebugserverconnection.h b/src/plugins/qmltooling/shared/qqmldebugserverconnection.h index 9bdb1bcc8b..3fac15acb2 100644 --- a/src/plugins/qmltooling/shared/qqmldebugserverconnection.h +++ b/src/plugins/qmltooling/shared/qqmldebugserverconnection.h @@ -1,31 +1,37 @@ /**************************************************************************** ** -** Copyright (C) 2015 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQml module of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL21$ +** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms -** and conditions see http://www.qt.io/terms-conditions. For further -** information use the contact form at http://www.qt.io/contact-us. +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. ** ** 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 or version 3 as published by the Free -** Software Foundation and appearing in the file LICENSE.LGPLv21 and -** LICENSE.LGPLv3 included in the packaging of this file. Please review the -** following information to ensure the GNU Lesser General Public License -** requirements will be met: https://www.gnu.org/licenses/lgpl.html and -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** -** As a special exception, The Qt Company gives you certain additional -** rights. These rights are described in The Qt Company 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 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** |