aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/qmltooling/qmldbg_inspector/abstractviewinspector.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/qmltooling/qmldbg_inspector/abstractviewinspector.cpp')
-rw-r--r--src/plugins/qmltooling/qmldbg_inspector/abstractviewinspector.cpp419
1 files changed, 419 insertions, 0 deletions
diff --git a/src/plugins/qmltooling/qmldbg_inspector/abstractviewinspector.cpp b/src/plugins/qmltooling/qmldbg_inspector/abstractviewinspector.cpp
new file mode 100644
index 0000000000..fa6dca7aca
--- /dev/null
+++ b/src/plugins/qmltooling/qmldbg_inspector/abstractviewinspector.cpp
@@ -0,0 +1,419 @@
+/****************************************************************************
+**
+** 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