aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/qmltooling/qmldbg_inspector
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/qmltooling/qmldbg_inspector')
-rw-r--r--src/plugins/qmltooling/qmldbg_inspector/abstracttool.cpp50
-rw-r--r--src/plugins/qmltooling/qmldbg_inspector/abstracttool.h85
-rw-r--r--src/plugins/qmltooling/qmldbg_inspector/abstractviewinspector.cpp419
-rw-r--r--src/plugins/qmltooling/qmldbg_inspector/abstractviewinspector.h126
-rw-r--r--src/plugins/qmltooling/qmldbg_inspector/highlight.cpp199
-rw-r--r--src/plugins/qmltooling/qmldbg_inspector/highlight.h111
-rw-r--r--src/plugins/qmltooling/qmldbg_inspector/inspecttool.cpp427
-rw-r--r--src/plugins/qmltooling/qmldbg_inspector/inspecttool.h127
-rw-r--r--src/plugins/qmltooling/qmldbg_inspector/qmldbg_inspector.pro27
-rw-r--r--src/plugins/qmltooling/qmldbg_inspector/qqmlinspectorservice.cpp127
-rw-r--r--src/plugins/qmltooling/qmldbg_inspector/qqmlinspectorservice.json3
-rw-r--r--src/plugins/qmltooling/qmldbg_inspector/qqmlinspectorservicefactory.h66
-rw-r--r--src/plugins/qmltooling/qmldbg_inspector/qquickviewinspector.cpp377
-rw-r--r--src/plugins/qmltooling/qmldbg_inspector/qquickviewinspector.h109
14 files changed, 2253 insertions, 0 deletions
diff --git a/src/plugins/qmltooling/qmldbg_inspector/abstracttool.cpp b/src/plugins/qmltooling/qmldbg_inspector/abstracttool.cpp
new file mode 100644
index 0000000000..3e059bed13
--- /dev/null
+++ b/src/plugins/qmltooling/qmldbg_inspector/abstracttool.cpp
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..c796925866
--- /dev/null
+++ b/src/plugins/qmltooling/qmldbg_inspector/abstracttool.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** 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
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
diff --git a/src/plugins/qmltooling/qmldbg_inspector/abstractviewinspector.h b/src/plugins/qmltooling/qmldbg_inspector/abstractviewinspector.h
new file mode 100644
index 0000000000..8f7ad4ac5b
--- /dev/null
+++ b/src/plugins/qmltooling/qmldbg_inspector/abstractviewinspector.h
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** 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/highlight.cpp b/src/plugins/qmltooling/qmldbg_inspector/highlight.cpp
new file mode 100644
index 0000000000..4d4e3aa720
--- /dev/null
+++ b/src/plugins/qmltooling/qmldbg_inspector/highlight.cpp
@@ -0,0 +1,199 @@
+/****************************************************************************
+**
+** 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 "highlight.h"
+
+#include <QtCore/QTimer>
+#include <QtGui/QPainter>
+#include <QtGui/QStaticText>
+#include <QtQuick/QQuickWindow>
+
+QT_BEGIN_NAMESPACE
+
+namespace QmlJSDebugger {
+
+Highlight::Highlight(QQuickItem *parent) : QQuickPaintedItem(parent)
+{
+ initRenderDetails();
+}
+
+Highlight::Highlight(QQuickItem *item, QQuickItem *parent)
+ : QQuickPaintedItem(parent)
+{
+ initRenderDetails();
+ setItem(item);
+}
+
+void Highlight::initRenderDetails()
+{
+ setRenderTarget(QQuickPaintedItem::FramebufferObject);
+ setPerformanceHint(QQuickPaintedItem::FastFBOResizing, true);
+}
+
+void Highlight::setItem(QQuickItem *item)
+{
+ if (m_item)
+ m_item->disconnect(this);
+
+ if (item) {
+ connect(item, SIGNAL(xChanged()), SLOT(adjust()));
+ connect(item, SIGNAL(yChanged()), SLOT(adjust()));
+ connect(item, SIGNAL(widthChanged()), SLOT(adjust()));
+ connect(item, SIGNAL(heightChanged()), SLOT(adjust()));
+ connect(item, SIGNAL(rotationChanged()), SLOT(adjust()));
+ connect(item, SIGNAL(transformOriginChanged(TransformOrigin)),
+ SLOT(adjust()));
+ }
+ QQuickWindow *view = item->window();
+ QQuickItem * contentItem = view->contentItem();
+ if (contentItem) {
+ connect(contentItem, SIGNAL(xChanged()), SLOT(adjust()));
+ connect(contentItem, SIGNAL(yChanged()), SLOT(adjust()));
+ connect(contentItem, SIGNAL(widthChanged()), SLOT(adjust()));
+ connect(contentItem, SIGNAL(heightChanged()), SLOT(adjust()));
+ connect(contentItem, SIGNAL(rotationChanged()), SLOT(adjust()));
+ connect(contentItem, SIGNAL(transformOriginChanged(TransformOrigin)),
+ SLOT(adjust()));
+ }
+ m_item = item;
+ setContentsSize(view->size());
+ adjust();
+}
+
+void Highlight::adjust()
+{
+ if (!m_item)
+ return;
+
+ bool success = false;
+ m_transform = m_item->itemTransform(0, &success);
+ if (!success)
+ m_transform = QTransform();
+
+ setSize(QSizeF(m_item->width(), m_item->height()));
+ qreal scaleFactor = 1;
+ QPointF originOffset = QPointF(0,0);
+ QQuickWindow *view = m_item->window();
+ if (view->contentItem()) {
+ scaleFactor = view->contentItem()->scale();
+ originOffset -= view->contentItem()->position();
+ }
+ // The scale transform for the overlay needs to be cancelled
+ // as the Item's transform which will be applied to the painter
+ // takes care of it.
+ parentItem()->setScale(1/scaleFactor);
+ setPosition(originOffset);
+ update();
+}
+
+
+void HoverHighlight::paint(QPainter *painter)
+{
+ if (!item())
+ return;
+
+ painter->save();
+ painter->setTransform(transform());
+ painter->setPen(QColor(108, 141, 221));
+ painter->drawRect(QRect(0, 0, item()->width() - 1, item()->height() - 1));
+ painter->restore();
+}
+
+
+SelectionHighlight::SelectionHighlight(const QString &name, QQuickItem *item, QQuickItem *parent)
+ : Highlight(item, parent),
+ m_name(name),
+ m_nameDisplayActive(false)
+{
+}
+
+void SelectionHighlight::paint(QPainter *painter)
+{
+ if (!item())
+ return;
+ painter->save();
+ painter->fillRect(QRectF(0,0,contentsSize().width(), contentsSize().height()),
+ QColor(0,0,0,127));
+ painter->setTransform(transform());
+ // Setting the composition mode such that the transparency will
+ // be erased as per the selected item.
+ painter->setCompositionMode(QPainter::CompositionMode_Clear);
+ painter->fillRect(0, 0, item()->width(), item()->height(), Qt::black);
+ painter->restore();
+
+ // Use the painter with the original transform and not with the
+ // item's transform for display of name.
+ if (!m_nameDisplayActive)
+ return;
+
+ // Paint the text in gray background if display name is active..
+ QRect textRect = painter->boundingRect(QRect(10, contentsSize().height() - 10 ,
+ contentsSize().width() - 20, contentsSize().height()),
+ Qt::AlignCenter | Qt::ElideRight, m_name);
+
+ qreal xPosition = m_displayPoint.x();
+ if (xPosition + textRect.width() > contentsSize().width())
+ xPosition = contentsSize().width() - textRect.width();
+ if (xPosition < 0) {
+ xPosition = 0;
+ textRect.setWidth(contentsSize().width());
+ }
+ qreal yPosition = m_displayPoint.y() - textRect.height() - 20;
+ if (yPosition < 50 )
+ yPosition = 50;
+
+ painter->fillRect(QRectF(xPosition - 5, yPosition - 5,
+ textRect.width() + 10, textRect.height() + 10), Qt::gray);
+ painter->drawRect(QRectF(xPosition - 5, yPosition - 5,
+ textRect.width() + 10, textRect.height() + 10));
+
+ painter->drawStaticText(xPosition, yPosition, QStaticText(m_name));
+}
+
+void SelectionHighlight::showName(const QPointF &displayPoint)
+{
+ m_displayPoint = displayPoint;
+ m_nameDisplayActive = true;
+ QTimer::singleShot(1500, this, SLOT(disableNameDisplay()));
+ update();
+}
+
+void SelectionHighlight::disableNameDisplay()
+{
+ m_nameDisplayActive = false;
+ update();
+}
+
+} // namespace QmlJSDebugger
+
+QT_END_NAMESPACE
diff --git a/src/plugins/qmltooling/qmldbg_inspector/highlight.h b/src/plugins/qmltooling/qmldbg_inspector/highlight.h
new file mode 100644
index 0000000000..05f6382353
--- /dev/null
+++ b/src/plugins/qmltooling/qmldbg_inspector/highlight.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** 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 HIGHLIGHT_H
+#define HIGHLIGHT_H
+
+#include <QtCore/QPointer>
+#include <QtCore/QPointF>
+#include <QtGui/QTransform>
+#include <QtQuick/QQuickPaintedItem>
+
+QT_BEGIN_NAMESPACE
+
+namespace QmlJSDebugger {
+
+class Highlight : public QQuickPaintedItem
+{
+ Q_OBJECT
+
+public:
+ Highlight(QQuickItem *parent);
+ Highlight(QQuickItem *item, QQuickItem *parent);
+
+ void setItem(QQuickItem *item);
+ QQuickItem *item() {return m_item;}
+
+protected:
+ QTransform transform() {return m_transform;}
+
+private:
+ void initRenderDetails();
+
+private slots:
+ void adjust();
+
+private:
+ QPointer<QQuickItem> m_item;
+ QTransform m_transform;
+};
+
+/**
+ * A highlight suitable for indicating selection.
+ */
+class SelectionHighlight : public Highlight
+{
+ Q_OBJECT
+
+public:
+ SelectionHighlight(const QString &name, QQuickItem *item, QQuickItem *parent);
+ void paint(QPainter *painter);
+ void showName(const QPointF &displayPoint);
+
+private slots:
+ void disableNameDisplay();
+
+private:
+ QPointF m_displayPoint;
+ QString m_name;
+ bool m_nameDisplayActive;
+};
+
+/**
+ * A highlight suitable for indicating hover.
+ */
+class HoverHighlight : public Highlight
+{
+public:
+ HoverHighlight(QQuickItem *parent)
+ : Highlight(parent)
+ {
+ setZ(1); // hover highlight on top of selection highlight
+ }
+
+ void paint(QPainter *painter);
+};
+
+} // namespace QmlJSDebugger
+
+QT_END_NAMESPACE
+
+#endif // HIGHLIGHT_H
diff --git a/src/plugins/qmltooling/qmldbg_inspector/inspecttool.cpp b/src/plugins/qmltooling/qmldbg_inspector/inspecttool.cpp
new file mode 100644
index 0000000000..cc6b4ffb8c
--- /dev/null
+++ b/src/plugins/qmltooling/qmldbg_inspector/inspecttool.cpp
@@ -0,0 +1,427 @@
+/****************************************************************************
+**
+** 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 "inspecttool.h"
+
+#include "highlight.h"
+#include "qquickviewinspector.h"
+
+#include <QtCore/QLineF>
+
+#include <QtGui/QMouseEvent>
+#include <QtGui/QWheelEvent>
+#include <QtGui/QTouchEvent>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QGuiApplication>
+#include <QtGui/QStyleHints>
+
+#include <QtQuick/QQuickView>
+#include <QtQuick/QQuickItem>
+
+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),
+ 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);
+}
+
+InspectTool::~InspectTool()
+{
+ 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);
+ }
+ }
+}
+
+void InspectTool::leaveEvent(QEvent *)
+{
+ m_hoverHighlight->setVisible(false);
+}
+
+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);
+ }
+}
+
+void InspectTool::mouseDoubleClickEvent(QMouseEvent *event)
+{
+ m_mousePosition = event->localPos();
+ m_pressAndHoldTimer.stop();
+ if (event->button() == Qt::LeftButton) {
+ selectNextItem();
+ m_hoverHighlight->setVisible(false);
+ }
+}
+
+void InspectTool::mouseMoveEvent(QMouseEvent *event)
+{
+ m_mousePosition = event->localPos();
+ moveItem(event->buttons() & Qt::LeftButton);
+}
+
+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);
+ } else {
+ m_hoverHighlight->setItem(item);
+ m_hoverHighlight->setVisible(true);
+ }
+}
+
+#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();
+
+ 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;
+ }
+ break;
+ case QEvent::TouchUpdate: {
+ if (touchPoints.count() > 1)
+ m_tapEvent = false;
+ 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) {
+ m_tapEvent = false;
+ bool doubleTap = event->timestamp() - m_touchTimestamp
+ < static_cast<ulong>(QGuiApplication::styleHints()->mouseDoubleClickInterval());
+ if (doubleTap) {
+ m_nameDisplayTimer.stop();
+ selectNextItem();
+ }
+ else {
+ selectItem();
+ }
+ m_touchTimestamp = event->timestamp();
+ }
+ m_didPressAndHold = false;
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+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))
+ return;
+ QList<QQuickItem*> items = inspector()->itemsAt(m_mousePosition);
+ for (int i = 0; i < items.count(); i++) {
+ if (m_lastItem == items[i]) {
+ if (i + 1 < items.count())
+ m_lastItem = items[i+1];
+ else
+ m_lastItem = items[0];
+ inspector()->setSelectedItems(QList<QQuickItem*>() << m_lastItem);
+ showSelectedItemName();
+ break;
+ }
+ }
+}
+
+void InspectTool::selectItem()
+{
+ if (!inspector()->topVisibleItemAt(m_mousePosition))
+ return;
+ if (m_lastClickedItem == inspector()->topVisibleItemAt(m_mousePosition)) {
+ m_nameDisplayTimer.start();
+ return;
+ }
+ m_lastClickedItem = inspector()->topVisibleItemAt(m_mousePosition);
+ m_lastItem = m_lastClickedItem;
+ inspector()->setSelectedItems(QList<QQuickItem*>() << m_lastClickedItem);
+ showSelectedItemName();
+}
+
+QQuickViewInspector *InspectTool::inspector() const
+{
+ return static_cast<QQuickViewInspector*>(AbstractTool::inspector());
+}
+
+void InspectTool::showSelectedItemName()
+{
+ inspector()->showSelectedItemName(m_lastItem, m_mousePosition);
+}
+
+} // namespace QmlJSDebugger
+
+QT_END_NAMESPACE
diff --git a/src/plugins/qmltooling/qmldbg_inspector/inspecttool.h b/src/plugins/qmltooling/qmldbg_inspector/inspecttool.h
new file mode 100644
index 0000000000..fdb763d4b3
--- /dev/null
+++ b/src/plugins/qmltooling/qmldbg_inspector/inspecttool.h
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** 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 INSPECTTOOL_H
+#define INSPECTTOOL_H
+
+#include "abstracttool.h"
+
+#include <QtCore/QPointF>
+#include <QtCore/QPointer>
+#include <QtCore/QTimer>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickView;
+class QQuickItem;
+
+namespace QmlJSDebugger {
+
+class QQuickViewInspector;
+class HoverHighlight;
+
+class InspectTool : public AbstractTool
+{
+ Q_OBJECT
+public:
+ enum ZoomDirection {
+ ZoomIn,
+ ZoomOut
+ };
+
+ InspectTool(QQuickViewInspector *inspector, QQuickView *view);
+ ~InspectTool();
+
+ void enable(bool enable);
+
+ 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();
+
+private slots:
+ void zoomTo100();
+ void showSelectedItemName();
+
+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;
+ QQuickItem *m_lastItem;
+ QQuickItem *m_lastClickedItem;
+};
+
+} // namespace QmlJSDebugger
+
+QT_END_NAMESPACE
+
+#endif // INSPECTTOOL_H
diff --git a/src/plugins/qmltooling/qmldbg_inspector/qmldbg_inspector.pro b/src/plugins/qmltooling/qmldbg_inspector/qmldbg_inspector.pro
new file mode 100644
index 0000000000..1c3e5f387b
--- /dev/null
+++ b/src/plugins/qmltooling/qmldbg_inspector/qmldbg_inspector.pro
@@ -0,0 +1,27 @@
+TARGET = qmldbg_inspector
+QT += qml-private quick-private core-private gui-private
+
+PLUGIN_TYPE = qmltooling
+PLUGIN_CLASS_NAME = QQmlInspectorServiceFactory
+load(qt_plugin)
+
+INCLUDEPATH *= $$PWD $$PWD/../shared
+
+SOURCES += \
+ $$PWD/highlight.cpp \
+ $$PWD/qquickviewinspector.cpp \
+ $$PWD/abstracttool.cpp \
+ $$PWD/abstractviewinspector.cpp \
+ $$PWD/inspecttool.cpp \
+ $$PWD/qqmlinspectorservice.cpp
+
+HEADERS += \
+ $$PWD/highlight.h \
+ $$PWD/qquickviewinspector.h \
+ $$PWD/qqmlinspectorservicefactory.h \
+ $$PWD/abstracttool.h \
+ $$PWD/abstractviewinspector.h \
+ $$PWD/inspecttool.h
+
+OTHER_FILES += \
+ qqmlinspectorservice.json
diff --git a/src/plugins/qmltooling/qmldbg_inspector/qqmlinspectorservice.cpp b/src/plugins/qmltooling/qmldbg_inspector/qqmlinspectorservice.cpp
new file mode 100644
index 0000000000..1707091df3
--- /dev/null
+++ b/src/plugins/qmltooling/qmldbg_inspector/qqmlinspectorservice.cpp
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** 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 "qqmlinspectorservicefactory.h"
+#include "qquickviewinspector.h"
+
+#include <private/qqmlglobal_p.h>
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QPluginLoader>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlInspectorServiceImpl : public QQmlInspectorService
+{
+ Q_OBJECT
+
+public:
+ QQmlInspectorServiceImpl(QObject *parent = 0);
+
+ void addView(QObject *);
+ void removeView(QObject *);
+
+protected:
+ virtual void stateChanged(State state);
+ virtual void messageReceived(const QByteArray &);
+
+private Q_SLOTS:
+ void processMessage(const QByteArray &message);
+ void updateState();
+
+private:
+ friend class QQmlInspectorServiceFactory;
+
+ QList<QObject*> m_views;
+ QmlJSDebugger::AbstractViewInspector *m_currentInspector;
+};
+
+QQmlInspectorServiceImpl::QQmlInspectorServiceImpl(QObject *parent):
+ QQmlInspectorService(1, parent), m_currentInspector(0)
+{
+}
+
+void QQmlInspectorServiceImpl::addView(QObject *view)
+{
+ m_views.append(view);
+ updateState();
+}
+
+void QQmlInspectorServiceImpl::removeView(QObject *view)
+{
+ m_views.removeAll(view);
+ updateState();
+}
+
+void QQmlInspectorServiceImpl::stateChanged(State /*state*/)
+{
+ QMetaObject::invokeMethod(this, "updateState", Qt::QueuedConnection);
+}
+
+void QQmlInspectorServiceImpl::updateState()
+{
+ 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);
+ else
+ qWarning() << "QQmlInspector: No inspector available for view '"
+ << m_views.first()->metaObject()->className() << "'.";
+}
+
+void QQmlInspectorServiceImpl::messageReceived(const QByteArray &message)
+{
+ QMetaObject::invokeMethod(this, "processMessage", Qt::QueuedConnection, Q_ARG(QByteArray, message));
+}
+
+void QQmlInspectorServiceImpl::processMessage(const QByteArray &message)
+{
+ if (m_currentInspector)
+ m_currentInspector->handleMessage(message);
+}
+
+QQmlDebugService *QQmlInspectorServiceFactory::create(const QString &key)
+{
+ return key == QQmlInspectorServiceImpl::s_key ? new QQmlInspectorServiceImpl(this) : 0;
+}
+
+QT_END_NAMESPACE
+
+#include "qqmlinspectorservice.moc"
diff --git a/src/plugins/qmltooling/qmldbg_inspector/qqmlinspectorservice.json b/src/plugins/qmltooling/qmldbg_inspector/qqmlinspectorservice.json
new file mode 100644
index 0000000000..9ace8dad2f
--- /dev/null
+++ b/src/plugins/qmltooling/qmldbg_inspector/qqmlinspectorservice.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "QmlInspector" ]
+}
diff --git a/src/plugins/qmltooling/qmldbg_inspector/qqmlinspectorservicefactory.h b/src/plugins/qmltooling/qmldbg_inspector/qqmlinspectorservicefactory.h
new file mode 100644
index 0000000000..52f84a362d
--- /dev/null
+++ b/src/plugins/qmltooling/qmldbg_inspector/qqmlinspectorservicefactory.h
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** 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 QQMLINSPECTORSERVICE_H
+#define QQMLINSPECTORSERVICE_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 <private/qqmldebugserviceinterfaces_p.h>
+#include <private/qqmldebugservicefactory_p.h>
+
+#include <QtQml/qtqmlglobal.h>
+#include <QtCore/QList>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlInspectorServiceFactory : public QQmlDebugServiceFactory
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlDebugServiceFactory_iid FILE "qqmlinspectorservice.json")
+public:
+ QQmlDebugService *create(const QString &key);
+};
+
+QT_END_NAMESPACE
+
+#endif // QQMLINSPECTORSERVICE_H
diff --git a/src/plugins/qmltooling/qmldbg_inspector/qquickviewinspector.cpp b/src/plugins/qmltooling/qmldbg_inspector/qquickviewinspector.cpp
new file mode 100644
index 0000000000..de9d5617b5
--- /dev/null
+++ b/src/plugins/qmltooling/qmldbg_inspector/qquickviewinspector.cpp
@@ -0,0 +1,377 @@
+/****************************************************************************
+**
+** 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
new file mode 100644
index 0000000000..e823e5a03d
--- /dev/null
+++ b/src/plugins/qmltooling/qmldbg_inspector/qquickviewinspector.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** 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