diff --git a/src/plugins/qmljsinspector/qmljsclientproxy.cpp b/src/plugins/qmljsinspector/qmljsclientproxy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..abceafd0cad788519f8343800124b604b15aacde --- /dev/null +++ b/src/plugins/qmljsinspector/qmljsclientproxy.cpp @@ -0,0 +1,301 @@ +#include "qmljsclientproxy.h" +#include "qmljsdebuggerclient.h" + +#include <utils/qtcassert.h> + +#include <private/qdeclarativedebug_p.h> +#include <private/qdeclarativedebugclient_p.h> + +#include <QUrl> +#include <QAbstractSocket> +#include <QDebug> + +using namespace QmlJSInspector::Internal; + +ClientProxy *ClientProxy::m_instance = 0; + +ClientProxy::ClientProxy(QObject *parent) : + QObject(parent), + m_conn(0), + m_client(0), + m_engineQuery(0), + m_contextQuery(0), + m_objectTreeQuery(0), + m_debuggerRunControl(0) +{ + m_instance = this; +} + +ClientProxy *ClientProxy::instance() +{ + return m_instance; +} + +bool ClientProxy::connectToViewer(const QString &host, quint16 port) +{ + if (m_conn && m_conn->state() != QAbstractSocket::UnconnectedState) + return false; + + qDebug() << Q_FUNC_INFO; + if (m_client) { + disconnect(m_client, SIGNAL(propertyDumpReceived(QDeclarativeDebugPropertyDump)), + this, SIGNAL(propertyDumpReceived(QDeclarativeDebugPropertyDump))); + disconnect(m_client, SIGNAL(selectedItemsChanged(QList<QDeclarativeDebugObjectReference>)), + this, SIGNAL(selectedItemsChanged(QList<QDeclarativeDebugObjectReference>))); + + emit aboutToDisconnect(); + + delete m_client; m_client = 0; + } + + if (m_conn) { + m_conn->disconnectFromHost(); + delete m_conn; + m_conn = 0; + } + + m_conn = new QDeclarativeDebugConnection(this); + connect(m_conn, SIGNAL(stateChanged(QAbstractSocket::SocketState)), + SLOT(connectionStateChanged())); + connect(m_conn, SIGNAL(error(QAbstractSocket::SocketError)), + SLOT(connectionError())); + + emit connectionStatusMessage(tr("[Inspector] set to connect to debug server %1:%2").arg(host).arg(port)); + m_conn->connectToHost(host, port); + + + // blocks until connected; if no connection is available, will fail immediately + if (!m_conn->waitForConnected()) + return false; + +// ### commented out as the code resulted in asserts +// QTC_ASSERT(m_debuggerRunControl, return false); +// Debugger::Internal::QmlEngine *engine = qobject_cast<Debugger::Internal::QmlEngine *>(m_debuggerRunControl->engine()); +// QTC_ASSERT(engine, return false); +// (void) new DebuggerClient(m_conn, engine); + + return true; +} + +void ClientProxy::disconnectFromViewer() +{ + m_conn->disconnectFromHost(); + emit disconnected(); +} + +void ClientProxy::connectionError() +{ + emit connectionStatusMessage(tr("[Inspector] error: (%1) %2", "%1=error code, %2=error message") + .arg(m_conn->error()).arg(m_conn->errorString())); +} + +void ClientProxy::connectionStateChanged() +{ + switch (m_conn->state()) { + case QAbstractSocket::UnconnectedState: + { + emit connectionStatusMessage(tr("[Inspector] disconnected.\n\n")); + + delete m_engineQuery; + m_engineQuery = 0; + delete m_contextQuery; + m_contextQuery = 0; + + if (m_objectTreeQuery) { + delete m_objectTreeQuery; + m_objectTreeQuery = 0; + } + + emit disconnected(); + + break; + } + case QAbstractSocket::HostLookupState: + emit connectionStatusMessage(tr("[Inspector] resolving host...")); + break; + case QAbstractSocket::ConnectingState: + emit connectionStatusMessage(tr("[Inspector] connecting to debug server...")); + break; + case QAbstractSocket::ConnectedState: + { + emit connectionStatusMessage(tr("[Inspector] connected.\n")); + + if (!m_client) { + qDebug() << "CREATING ENGINE"; + m_client = new QDeclarativeEngineDebug(m_conn, this); + emit connected(m_client); + + connect(m_client, + SIGNAL(propertyDumpReceived(QDeclarativeDebugPropertyDump)), + SIGNAL(propertyDumpReceived(QDeclarativeDebugPropertyDump))); + connect(m_client, + SIGNAL(selectedItemsChanged(QList<QDeclarativeDebugObjectReference>)), + SIGNAL(selectedItemsChanged(QList<QDeclarativeDebugObjectReference>))); + } + + reloadEngines(); + + break; + } + case QAbstractSocket::ClosingState: + emit connectionStatusMessage(tr("[Inspector] closing...")); + break; + case QAbstractSocket::BoundState: + case QAbstractSocket::ListeningState: + break; + } +} + +bool ClientProxy::isConnected() const +{ + return (m_conn && m_client && m_conn->state() == QAbstractSocket::ConnectedState); +} + +bool ClientProxy::isUnconnected() const +{ + return (!m_conn || m_conn->state() == QAbstractSocket::UnconnectedState); +} + +void ClientProxy::setSelectedItemByObjectId(int engineId, const QDeclarativeDebugObjectReference &objectRef) +{ + qDebug() << "TODO:" << Q_FUNC_INFO; +#if 0 + if (isConnected()) + m_client->setSelectedItemByObjectId(engineId, objectRef); +#endif +} + +QList<QDeclarativeDebugObjectReference> ClientProxy::objectReferences(const QUrl &url) const +{ + return objectReferences(url, m_rootObject); +} + +QList<QDeclarativeDebugObjectReference> ClientProxy::objectReferences(const QUrl &url, + const QDeclarativeDebugObjectReference &objectRef) const +{ + QList<QDeclarativeDebugObjectReference> result; + if (objectRef.source().url() == url) + result.append(objectRef); + + foreach(const QDeclarativeDebugObjectReference &child, objectRef.children()) { + result.append(objectReferences(url, child)); + } + + return result; +} + +QDeclarativeDebugExpressionQuery *ClientProxy::setBindingForObject(int objectDebugId, + const QString &propertyName, + const QVariant &value, + bool isLiteralValue) +{ + qDebug() << "TODO:" << Q_FUNC_INFO; +#if 0 + if (propertyName == QLatin1String("id") || objectDebugId == -1) + return 0; + + qDebug() << "executeBinding():" << objectDebugId << propertyName << value << "isLiteral:" << isLiteralValue; + + return m_client->setBindingForObject(objectDebugId, propertyName, value.toString(), isLiteralValue, 0); +#else + return 0; +#endif +} + +void ClientProxy::queryEngineContext(int id) +{ + if (id < 0) + return; + + if (m_contextQuery) { + delete m_contextQuery; + m_contextQuery = 0; + } + + m_contextQuery = m_client->queryRootContexts(QDeclarativeDebugEngineReference(id), this); + if (!m_contextQuery->isWaiting()) + contextChanged(); + else + QObject::connect(m_contextQuery, SIGNAL(stateChanged(QDeclarativeDebugQuery::State)), + this, SLOT(contextChanged())); +} + +void ClientProxy::contextChanged() +{ + if (m_contextQuery) { + + if (m_contextQuery->rootContext().objects().isEmpty()) { + m_rootObject = QDeclarativeDebugObjectReference(); + emit objectTreeUpdated(m_rootObject); + } else { + m_rootObject = m_contextQuery->rootContext().objects().first(); + } + + delete m_contextQuery; m_contextQuery = 0; + + m_objectTreeQuery = m_client->queryObjectRecursive(m_rootObject, this); + if (!m_objectTreeQuery->isWaiting()) { + objectTreeFetched(); + } else { + connect(m_objectTreeQuery, + SIGNAL(stateChanged(QDeclarativeDebugQuery::State)), + SLOT(objectTreeFetched(QDeclarativeDebugQuery::State))); + } + } + +} + +void ClientProxy::objectTreeFetched(QDeclarativeDebugQuery::State state) +{ + if (state != QDeclarativeDebugQuery::Completed) { + m_rootObject = QDeclarativeDebugObjectReference(); + return; + } + + m_rootObject = m_objectTreeQuery->object(); + + delete m_objectTreeQuery; + m_objectTreeQuery = 0; + + emit objectTreeUpdated(m_rootObject); +} + +void ClientProxy::reloadQmlViewer(int engineId) +{ + qDebug() << "TODO:" << Q_FUNC_INFO; +#if 0 + if (m_client && m_conn->isConnected()) { + m_client->reloadQmlViewer(engineId); + } +#endif +} + +void ClientProxy::reloadEngines() +{ + if (m_engineQuery) { + emit connectionStatusMessage("[Inspector] Waiting for response to previous engine query"); + return; + } + + emit aboutToReloadEngines(); + + m_engineQuery = m_client->queryAvailableEngines(this); + if (!m_engineQuery->isWaiting()) + updateEngineList(); + else + QObject::connect(m_engineQuery, SIGNAL(stateChanged(QDeclarativeDebugQuery::State)), + this, SLOT(updateEngineList())); +} + +QList<QDeclarativeDebugEngineReference> ClientProxy::engines() const +{ + return m_engines; +} + +void ClientProxy::updateEngineList() +{ + m_engines = m_engineQuery->engines(); + delete m_engineQuery; m_engineQuery = 0; + + emit enginesChanged(); +} diff --git a/src/plugins/qmljsinspector/qmljsclientproxy.h b/src/plugins/qmljsinspector/qmljsclientproxy.h new file mode 100644 index 0000000000000000000000000000000000000000..80ed41de9409f32f9cef529e18822d5eff7b76d3 --- /dev/null +++ b/src/plugins/qmljsinspector/qmljsclientproxy.h @@ -0,0 +1,101 @@ +#ifndef QMLJSCLIENTPROXY_H +#define QMLJSCLIENTPROXY_H + +#include "qmljsinspectorplugin.h" + +#include <private/qdeclarativedebug_p.h> +#include <QObject> + +QT_FORWARD_DECLARE_CLASS(QUrl) +QT_FORWARD_DECLARE_CLASS(QDeclarativeEngineDebug) +QT_FORWARD_DECLARE_CLASS(QDeclarativeDebugConnection) +QT_FORWARD_DECLARE_CLASS(QDeclarativeDebugExpressionQuery) +QT_FORWARD_DECLARE_CLASS(QDeclarativeDebugPropertyDump) + +namespace Debugger { + class DebuggerRunControl; +} + +namespace QmlJSInspector { +namespace Internal { + +class QmlInspectorPlugin; + +class ClientProxy : public QObject +{ + Q_OBJECT + +public: + static ClientProxy *instance(); + QDeclarativeDebugExpressionQuery *setBindingForObject(int objectDebugId, + const QString &propertyName, + const QVariant &value, + bool isLiteralValue); + + // returns the object references for the given url. + QList<QDeclarativeDebugObjectReference> objectReferences(const QUrl &url) const; + + bool isConnected() const; + bool isUnconnected() const; + + void setSelectedItemByObjectId(int engineId, const QDeclarativeDebugObjectReference &objectRef); + + bool connectToViewer(const QString &host, quint16 port); + void disconnectFromViewer(); + + QList<QDeclarativeDebugEngineReference> engines() const; + +signals: + void objectTreeUpdated(const QDeclarativeDebugObjectReference &rootObject); + void connectionStatusMessage(const QString &text); + + void aboutToReloadEngines(); + void enginesChanged(); + + void propertyDumpReceived(const QDeclarativeDebugPropertyDump &propertyDump); + void selectedItemsChanged(const QList<QDeclarativeDebugObjectReference> &selectedItems); + + void connected(QDeclarativeEngineDebug *client); + void aboutToDisconnect(); + void disconnected(); + +public slots: + void queryEngineContext(int id); + void reloadQmlViewer(int engineId); + +private slots: + void contextChanged(); + void connectionStateChanged(); + void connectionError(); + + void updateEngineList(); + void objectTreeFetched(QDeclarativeDebugQuery::State state = QDeclarativeDebugQuery::Completed); + +private: + void reloadEngines(); + QList<QDeclarativeDebugObjectReference> objectReferences(const QUrl &url, const QDeclarativeDebugObjectReference &objectRef) const; + +private: + explicit ClientProxy(QObject *parent = 0); + Q_DISABLE_COPY(ClientProxy); + + static ClientProxy *m_instance; + + QDeclarativeDebugConnection *m_conn; + QDeclarativeEngineDebug *m_client; + + QDeclarativeDebugEnginesQuery *m_engineQuery; + QDeclarativeDebugRootContextQuery *m_contextQuery; + QDeclarativeDebugObjectQuery *m_objectTreeQuery; + + QDeclarativeDebugObjectReference m_rootObject; + QList<QDeclarativeDebugEngineReference> m_engines; + + Debugger::DebuggerRunControl *m_debuggerRunControl; + friend class QmlJSInspector::Internal::QmlInspectorPlugin; +}; + +} // namespace Internal +} // namespace QmlJSInspector + +#endif // QMLJSCLIENTPROXY_H diff --git a/src/plugins/qmljsinspector/qmljsinspector.pro b/src/plugins/qmljsinspector/qmljsinspector.pro index 0f8b6abb015a4c3dbc71929481ec64501457acdd..67b65460fdbc28c16b07afa28166aa9a9e7e4f32 100644 --- a/src/plugins/qmljsinspector/qmljsinspector.pro +++ b/src/plugins/qmljsinspector/qmljsinspector.pro @@ -2,7 +2,7 @@ TEMPLATE = lib TARGET = QmlJSInspector INCLUDEPATH += . DEPENDPATH += . -QT += declarative +QT += declarative network include(../../private_headers.pri) @@ -13,12 +13,14 @@ qmljsdebuggerclient.h \ qmljsinspector_global.h \ qmljsinspectorconstants.h \ qmljsinspectorcontext.h \ -qmljsinspectorplugin.h +qmljsinspectorplugin.h \ +qmljsclientproxy.h SOURCES += \ qmljsdebuggerclient.cpp \ qmljsinspectorcontext.cpp \ -qmljsinspectorplugin.cpp +qmljsinspectorplugin.cpp \ +qmljsclientproxy.cpp OTHER_FILES += QmlJSInspector.pluginspec RESOURCES += qmljsinspector.qrc