Merge QML inspector into debugger plugin
Merge QmlJSInspector plugin into the debugger. Also merge the extra Inspector window with the Locals & Watchers: It now shows the QML object tree in the running state. Change-Id: I59ae0c1b970a48ba10ecda92ed3ba765d94b1d9c Reviewed-by: Aurindam Jana <aurindam.jana@nokia.com>
@@ -55,7 +55,6 @@ Project {
|
||||
"src/plugins/projectexplorer/projectexplorer.qbs",
|
||||
"src/plugins/qmldesigner/qmldesigner.qbs",
|
||||
"src/plugins/qmljseditor/qmljseditor.qbs",
|
||||
"src/plugins/qmljsinspector/qmljsinspector.qbs",
|
||||
"src/plugins/qmljstools/qmljstools.qbs",
|
||||
"src/plugins/qmlprofiler/qmlprofiler.qbs",
|
||||
"src/plugins/qmlprojectmanager/qmlprojectmanager.qbs",
|
||||
|
@@ -348,14 +348,16 @@ quint32 BaseEngineDebugClient::queryObjectRecursive(const QmlDebugObjectReferenc
|
||||
}
|
||||
|
||||
quint32 BaseEngineDebugClient::queryExpressionResult(int objectDebugId,
|
||||
const QString &expr)
|
||||
const QString &expr,
|
||||
int engineId)
|
||||
{
|
||||
quint32 id = 0;
|
||||
if (status() == QmlDebugClient::Enabled && objectDebugId != -1) {
|
||||
id = getId();
|
||||
QByteArray message;
|
||||
QDataStream ds(&message, QIODevice::WriteOnly);
|
||||
ds << QByteArray("EVAL_EXPRESSION") << id << objectDebugId << expr;
|
||||
ds << QByteArray("EVAL_EXPRESSION") << id << objectDebugId << expr
|
||||
<< engineId;
|
||||
sendMessage(message);
|
||||
}
|
||||
return id;
|
||||
|
@@ -66,7 +66,7 @@ public:
|
||||
quint32 queryObject(const QmlDebugObjectReference &object);
|
||||
quint32 queryObjectRecursive(const QmlDebugObjectReference &object);
|
||||
quint32 queryExpressionResult(int objectDebugId,
|
||||
const QString &expr);
|
||||
const QString &expr, int engineId = -1);
|
||||
virtual quint32 setBindingForObject(int objectDebugId, const QString &propertyName,
|
||||
const QVariant &bindingExpression,
|
||||
bool isLiteralValue,
|
||||
@@ -116,7 +116,7 @@ class QmlDebugEngineReference
|
||||
{
|
||||
public:
|
||||
QmlDebugEngineReference() : m_debugId(-1) {}
|
||||
QmlDebugEngineReference(int id) : m_debugId(id) {}
|
||||
explicit QmlDebugEngineReference(int id) : m_debugId(id) {}
|
||||
|
||||
int debugId() const { return m_debugId; }
|
||||
QString name() const { return m_name; }
|
||||
@@ -133,7 +133,7 @@ class QmlDebugObjectReference
|
||||
{
|
||||
public:
|
||||
QmlDebugObjectReference() : m_debugId(-1), m_parentId(-1), m_contextDebugId(-1), m_needsMoreData(false) {}
|
||||
QmlDebugObjectReference(int id) : m_debugId(id), m_parentId(-1), m_contextDebugId(-1), m_needsMoreData(false) {}
|
||||
explicit QmlDebugObjectReference(int id) : m_debugId(id), m_parentId(-1), m_contextDebugId(-1), m_needsMoreData(false) {}
|
||||
|
||||
int debugId() const { return m_debugId; }
|
||||
int parentId() const { return m_parentId; }
|
||||
@@ -148,18 +148,18 @@ public:
|
||||
QList<QmlDebugPropertyReference> properties() const { return m_properties; }
|
||||
QList<QmlDebugObjectReference> children() const { return m_children; }
|
||||
|
||||
bool insertObjectInTree(const QmlDebugObjectReference &obj)
|
||||
int insertObjectInTree(const QmlDebugObjectReference &obj)
|
||||
{
|
||||
for (int i = 0; i < m_children.count(); i++) {
|
||||
if (m_children[i].debugId() == obj.debugId()) {
|
||||
m_children.replace(i, obj);
|
||||
return true;
|
||||
return debugId();
|
||||
} else {
|
||||
if (m_children[i].insertObjectInTree(obj))
|
||||
return true;
|
||||
return debugId();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool operator ==(const QmlDebugObjectReference &obj)
|
||||
@@ -229,4 +229,20 @@ Q_DECLARE_METATYPE(QmlDebug::QmlDebugEngineReference)
|
||||
Q_DECLARE_METATYPE(QmlDebug::QmlDebugEngineReferenceList)
|
||||
Q_DECLARE_METATYPE(QmlDebug::QmlDebugContextReference)
|
||||
|
||||
inline QDebug operator<<(QDebug dbg, const QmlDebug::QmlDebugEngineReference &ref) {
|
||||
dbg.nospace() << "(Engine " << ref.debugId() << "/" << ref.name() << ")";
|
||||
return dbg.space();
|
||||
}
|
||||
|
||||
inline QDebug operator<<(QDebug dbg, const QmlDebug::QmlDebugContextReference &ref) {
|
||||
dbg.nospace() << "(Context " << ref.debugId() << "/" << ref.name() << ")";
|
||||
return dbg.space();
|
||||
}
|
||||
|
||||
inline QDebug operator<<(QDebug dbg, const QmlDebug::QmlDebugObjectReference &ref) {
|
||||
dbg.nospace() << "(Object " << ref.debugId() << "/"
|
||||
<< (ref.idString().isEmpty() ? ref.idString() : ref.className()) << ")";
|
||||
return dbg.space();
|
||||
}
|
||||
|
||||
#endif // BASEENGINEDEBUGCLIENT_H
|
||||
|
@@ -31,10 +31,9 @@
|
||||
|
||||
#include "basetoolsclient.h"
|
||||
|
||||
namespace QmlJSInspector {
|
||||
namespace Internal {
|
||||
namespace QmlDebug {
|
||||
|
||||
BaseToolsClient::BaseToolsClient(QmlDebug::QmlDebugConnection* client, QLatin1String clientName)
|
||||
BaseToolsClient::BaseToolsClient(QmlDebugConnection* client, QLatin1String clientName)
|
||||
: QmlDebugClient(clientName, client)
|
||||
{
|
||||
setObjectName(clientName);
|
||||
@@ -45,14 +44,13 @@ void BaseToolsClient::statusChanged(Status status)
|
||||
emit connectedStatusChanged(status);
|
||||
}
|
||||
|
||||
void BaseToolsClient::recurseObjectIdList(const QmlDebug::QmlDebugObjectReference &ref,
|
||||
void BaseToolsClient::recurseObjectIdList(const QmlDebugObjectReference &ref,
|
||||
QList<int> &debugIds, QList<QString> &objectIds)
|
||||
{
|
||||
debugIds << ref.debugId();
|
||||
objectIds << ref.idString();
|
||||
foreach (const QmlDebug::QmlDebugObjectReference &child, ref.children())
|
||||
foreach (const QmlDebugObjectReference &child, ref.children())
|
||||
recurseObjectIdList(child, debugIds, objectIds);
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSInspector
|
||||
} // namespace QmlDebug
|
@@ -32,17 +32,16 @@
|
||||
#ifndef BASETOOLSCLIENT_H
|
||||
#define BASETOOLSCLIENT_H
|
||||
|
||||
#include <qmldebug/qmldebugclient.h>
|
||||
#include <qmldebug/baseenginedebugclient.h>
|
||||
#include "qmldebugclient.h"
|
||||
#include "baseenginedebugclient.h"
|
||||
|
||||
namespace QmlJSInspector {
|
||||
namespace Internal {
|
||||
namespace QmlDebug {
|
||||
|
||||
class BaseToolsClient : public QmlDebug::QmlDebugClient
|
||||
class QMLDEBUG_EXPORT BaseToolsClient : public QmlDebugClient
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
BaseToolsClient(QmlDebug::QmlDebugConnection* client, QLatin1String clientName);
|
||||
BaseToolsClient(QmlDebugConnection *client, QLatin1String clientName);
|
||||
|
||||
virtual void setCurrentObjects(const QList<int> &debugIds) = 0;
|
||||
virtual void reloadViewer() = 0;
|
||||
@@ -67,7 +66,7 @@ public:
|
||||
|
||||
// ### Qt 4.8: remove if we can have access to qdeclarativecontextdata or id's
|
||||
virtual void setObjectIdList(
|
||||
const QList<QmlDebug::QmlDebugObjectReference> &objectRoots) = 0;
|
||||
const QList<QmlDebugObjectReference> &objectRoots) = 0;
|
||||
|
||||
virtual void clearComponentCache() = 0;
|
||||
|
||||
@@ -89,7 +88,7 @@ signals:
|
||||
protected:
|
||||
void statusChanged(Status);
|
||||
|
||||
void recurseObjectIdList(const QmlDebug::QmlDebugObjectReference &ref,
|
||||
void recurseObjectIdList(const QmlDebugObjectReference &ref,
|
||||
QList<int> &debugIds, QList<QString> &objectIds);
|
||||
protected:
|
||||
enum LogDirection {
|
||||
@@ -98,7 +97,6 @@ protected:
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSInspector
|
||||
} // namespace QmlDebug
|
||||
|
||||
#endif // BASETOOLSCLIENT_H
|
@@ -30,16 +30,114 @@
|
||||
**************************************************************************/
|
||||
|
||||
#include "declarativetoolsclient.h"
|
||||
#include "qmljsclientproxy.h"
|
||||
#include "qmljsinspectorconstants.h"
|
||||
#include <QMetaEnum>
|
||||
#include <QStringList>
|
||||
|
||||
using namespace QmlJSDebugger;
|
||||
|
||||
namespace QmlJSInspector {
|
||||
namespace QmlDebug {
|
||||
namespace Internal {
|
||||
|
||||
namespace Constants {
|
||||
|
||||
enum DesignTool {
|
||||
NoTool = 0,
|
||||
SelectionToolMode = 1,
|
||||
MarqueeSelectionToolMode = 2,
|
||||
MoveToolMode = 3,
|
||||
ResizeToolMode = 4,
|
||||
ZoomMode = 6
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
class InspectorProtocol : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_ENUMS(Message Tool)
|
||||
|
||||
public:
|
||||
enum Message {
|
||||
AnimationSpeedChanged = 0,
|
||||
AnimationPausedChanged = 19, // highest value
|
||||
ChangeTool = 1,
|
||||
ClearComponentCache = 2,
|
||||
ColorChanged = 3,
|
||||
CreateObject = 5,
|
||||
CurrentObjectsChanged = 6,
|
||||
DestroyObject = 7,
|
||||
MoveObject = 8,
|
||||
ObjectIdList = 9,
|
||||
Reload = 10,
|
||||
Reloaded = 11,
|
||||
SetAnimationSpeed = 12,
|
||||
SetAnimationPaused = 18,
|
||||
SetCurrentObjects = 14,
|
||||
SetDesignMode = 15,
|
||||
ShowAppOnTop = 16,
|
||||
ToolChanged = 17
|
||||
};
|
||||
|
||||
enum Tool {
|
||||
ColorPickerTool,
|
||||
SelectMarqueeTool,
|
||||
SelectTool,
|
||||
ZoomTool
|
||||
};
|
||||
|
||||
static inline QString toString(Message message)
|
||||
{
|
||||
return staticMetaObject.enumerator(0).valueToKey(message);
|
||||
}
|
||||
|
||||
static inline QString toString(Tool tool)
|
||||
{
|
||||
return staticMetaObject.enumerator(1).valueToKey(tool);
|
||||
}
|
||||
};
|
||||
|
||||
inline QDataStream & operator<< (QDataStream &stream, InspectorProtocol::Message message)
|
||||
{
|
||||
return stream << static_cast<quint32>(message);
|
||||
}
|
||||
|
||||
inline QDataStream & operator>> (QDataStream &stream, InspectorProtocol::Message &message)
|
||||
{
|
||||
quint32 i;
|
||||
stream >> i;
|
||||
message = static_cast<InspectorProtocol::Message>(i);
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline QDebug operator<< (QDebug dbg, InspectorProtocol::Message message)
|
||||
{
|
||||
dbg << InspectorProtocol::toString(message);
|
||||
return dbg;
|
||||
}
|
||||
|
||||
inline QDataStream & operator<< (QDataStream &stream, InspectorProtocol::Tool tool)
|
||||
{
|
||||
return stream << static_cast<quint32>(tool);
|
||||
}
|
||||
|
||||
inline QDataStream & operator>> (QDataStream &stream, InspectorProtocol::Tool &tool)
|
||||
{
|
||||
quint32 i;
|
||||
stream >> i;
|
||||
tool = static_cast<InspectorProtocol::Tool>(i);
|
||||
return stream;
|
||||
}
|
||||
|
||||
inline QDebug operator<< (QDebug dbg, InspectorProtocol::Tool tool)
|
||||
{
|
||||
dbg << InspectorProtocol::toString(tool);
|
||||
return dbg;
|
||||
}
|
||||
|
||||
} // internal
|
||||
|
||||
using namespace Internal;
|
||||
|
||||
DeclarativeToolsClient::DeclarativeToolsClient(QmlDebugConnection *client)
|
||||
: BaseToolsClient(client,QLatin1String(Constants::QDECLARATIVE_OBSERVER_MODE)),
|
||||
: BaseToolsClient(client,QLatin1String("QDeclarativeObserverMode")),
|
||||
m_connection(client)
|
||||
{
|
||||
setObjectName(name());
|
||||
@@ -165,7 +263,7 @@ void DeclarativeToolsClient::setCurrentObjects(const QList<int> &debugIds)
|
||||
}
|
||||
|
||||
void DeclarativeToolsClient::setObjectIdList(
|
||||
const QList<QmlDebug::QmlDebugObjectReference> &objectRoots)
|
||||
const QList<QmlDebugObjectReference> &objectRoots)
|
||||
{
|
||||
QByteArray message;
|
||||
QDataStream ds(&message, QIODevice::WriteOnly);
|
||||
@@ -173,7 +271,7 @@ void DeclarativeToolsClient::setObjectIdList(
|
||||
QList<int> debugIds;
|
||||
QList<QString> objectIds;
|
||||
|
||||
foreach (const QmlDebug::QmlDebugObjectReference &ref, objectRoots)
|
||||
foreach (const QmlDebugObjectReference &ref, objectRoots)
|
||||
recurseObjectIdList(ref, debugIds, objectIds);
|
||||
|
||||
InspectorProtocol::Message cmd = InspectorProtocol::ObjectIdList;
|
||||
@@ -182,7 +280,7 @@ void DeclarativeToolsClient::setObjectIdList(
|
||||
|
||||
Q_ASSERT(debugIds.length() == objectIds.length());
|
||||
|
||||
for(int i = 0; i < debugIds.length(); ++i) {
|
||||
for (int i = 0; i < debugIds.length(); ++i) {
|
||||
ds << debugIds[i] << objectIds[i];
|
||||
}
|
||||
|
||||
@@ -423,7 +521,7 @@ void DeclarativeToolsClient::applyChangesFromQmlFile()
|
||||
}
|
||||
|
||||
void DeclarativeToolsClient::log(LogDirection direction,
|
||||
InspectorProtocol::Message message,
|
||||
int message,
|
||||
const QString &extra)
|
||||
{
|
||||
QString msg;
|
||||
@@ -432,11 +530,14 @@ void DeclarativeToolsClient::log(LogDirection direction,
|
||||
else
|
||||
msg += QLatin1String(" receiving ");
|
||||
|
||||
msg += InspectorProtocol::toString(message);
|
||||
InspectorProtocol::Message msgType
|
||||
= static_cast<InspectorProtocol::Message>(message);
|
||||
msg += InspectorProtocol::toString(msgType);
|
||||
msg += QLatin1Char(' ');
|
||||
msg += extra;
|
||||
emit logActivity(name(), msg);
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSInspector
|
||||
} // namespace QmlDebug
|
||||
|
||||
#include "declarativetoolsclient.moc"
|
@@ -34,16 +34,13 @@
|
||||
|
||||
#include "basetoolsclient.h"
|
||||
|
||||
#include <inspectorprotocol.h>
|
||||
namespace QmlDebug {
|
||||
|
||||
namespace QmlJSInspector {
|
||||
namespace Internal {
|
||||
|
||||
class DeclarativeToolsClient : public BaseToolsClient
|
||||
class QMLDEBUG_EXPORT DeclarativeToolsClient : public BaseToolsClient
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
DeclarativeToolsClient(QmlDebug::QmlDebugConnection *client);
|
||||
DeclarativeToolsClient(QmlDebugConnection *client);
|
||||
|
||||
void setCurrentObjects(const QList<int> &debugIds);
|
||||
void reloadViewer();
|
||||
@@ -67,7 +64,7 @@ public:
|
||||
QList<int> currentObjects() const;
|
||||
|
||||
// ### Qt 4.8: remove if we can have access to qdeclarativecontextdata or id's
|
||||
void setObjectIdList(const QList<QmlDebug::QmlDebugObjectReference> &objectRoots);
|
||||
void setObjectIdList(const QList<QmlDebugObjectReference> &objectRoots);
|
||||
|
||||
void clearComponentCache();
|
||||
|
||||
@@ -76,15 +73,14 @@ protected:
|
||||
|
||||
private:
|
||||
void log(LogDirection direction,
|
||||
QmlJSDebugger::InspectorProtocol::Message message,
|
||||
int message,
|
||||
const QString &extra = QString());
|
||||
|
||||
private:
|
||||
QList<int> m_currentDebugIds;
|
||||
QmlDebug::QmlDebugConnection *m_connection;
|
||||
QmlDebugConnection *m_connection;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSInspector
|
||||
} // namespace QmlDebug
|
||||
|
||||
#endif // DECLARATIVETOOLSCLIENT_H
|
@@ -19,7 +19,10 @@ HEADERS += \
|
||||
$$PWD/qv8profilerclient.h \
|
||||
$$PWD/qmldebugconstants.h \
|
||||
$$PWD/qdebugmessageclient.h \
|
||||
$$PWD/qmlenginedebugclient.h
|
||||
$$PWD/qmlenginedebugclient.h \
|
||||
$$PWD/basetoolsclient.h \
|
||||
$$PWD/declarativetoolsclient.h \
|
||||
$$PWD/qmltoolsclient.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/qmldebugclient.cpp \
|
||||
@@ -29,5 +32,8 @@ SOURCES += \
|
||||
$$PWD/qpacketprotocol.cpp \
|
||||
$$PWD/qv8profilerclient.cpp \
|
||||
$$PWD/qdebugmessageclient.cpp \
|
||||
$$PWD/qmlenginedebugclient.cpp
|
||||
$$PWD/qmlenginedebugclient.cpp \
|
||||
$$PWD/basetoolsclient.cpp \
|
||||
$$PWD/declarativetoolsclient.cpp \
|
||||
$$PWD/qmltoolsclient.cpp
|
||||
|
||||
|
@@ -20,6 +20,11 @@ QtcLibrary {
|
||||
files: [
|
||||
"baseenginedebugclient.cpp",
|
||||
"baseenginedebugclient.h",
|
||||
"basetoolsclient.cpp",
|
||||
"basetoolsclient.h",
|
||||
"declarativeenginedebugclient.h",
|
||||
"declarativetoolsclient.cpp",
|
||||
"declarativetoolsclient.h",
|
||||
"qdebugmessageclient.cpp",
|
||||
"qdebugmessageclient.h",
|
||||
"qmldebugclient.cpp",
|
||||
@@ -34,7 +39,6 @@ QtcLibrary {
|
||||
"qmlprofilertraceclient.h",
|
||||
"qpacketprotocol.cpp",
|
||||
"qpacketprotocol.h",
|
||||
"declarativeenginedebugclient.h",
|
||||
"qmlenginedebugclient.cpp",
|
||||
"qmlenginedebugclient.h",
|
||||
"qv8profilerclient.cpp",
|
||||
|
@@ -30,8 +30,7 @@
|
||||
**************************************************************************/
|
||||
|
||||
#include "qmltoolsclient.h"
|
||||
#include "qmljsclientproxy.h"
|
||||
#include "qmljsinspectorconstants.h"
|
||||
#include <QStringList>
|
||||
|
||||
//INSPECTOR SERVICE PROTOCOL
|
||||
// <HEADER><COMMAND><DATA>
|
||||
@@ -61,11 +60,10 @@ const char DESTROY_OBJECT[] = "destroyObject";
|
||||
const char MOVE_OBJECT[] = "moveObject";
|
||||
const char CLEAR_CACHE[] = "clearCache";
|
||||
|
||||
namespace QmlJSInspector {
|
||||
namespace Internal {
|
||||
namespace QmlDebug {
|
||||
|
||||
QmlToolsClient::QmlToolsClient(QmlDebugConnection *client)
|
||||
: BaseToolsClient(client, QLatin1String(Constants::QML_INSPECTOR)),
|
||||
: BaseToolsClient(client, QLatin1String("QmlInspector")),
|
||||
m_connection(client),
|
||||
m_requestId(0),
|
||||
m_slowDownFactor(1)
|
||||
@@ -328,5 +326,4 @@ void QmlToolsClient::log(LogDirection direction,
|
||||
emit logActivity(name(), msg);
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSInspector
|
||||
} // namespace QmlDebug
|
@@ -33,14 +33,14 @@
|
||||
#define QMLTOOLSCLIENT_H
|
||||
|
||||
#include "basetoolsclient.h"
|
||||
namespace QmlJSInspector {
|
||||
namespace Internal {
|
||||
|
||||
class QmlToolsClient : public BaseToolsClient
|
||||
namespace QmlDebug {
|
||||
|
||||
class QMLDEBUG_EXPORT QmlToolsClient : public BaseToolsClient
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QmlToolsClient(QmlDebug::QmlDebugConnection *client);
|
||||
explicit QmlToolsClient(QmlDebugConnection *client);
|
||||
|
||||
void setCurrentObjects(const QList<int> &debugIds);
|
||||
void reloadViewer();
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
QList<int> currentObjects() const;
|
||||
|
||||
// ### Qt 4.8: remove if we can have access to qdeclarativecontextdata or id's
|
||||
void setObjectIdList(const QList<QmlDebug::QmlDebugObjectReference> &objectRoots);
|
||||
void setObjectIdList(const QList<QmlDebugObjectReference> &objectRoots);
|
||||
|
||||
void clearComponentCache();
|
||||
|
||||
@@ -78,12 +78,11 @@ private:
|
||||
|
||||
private:
|
||||
QList<int> m_currentDebugIds;
|
||||
QmlDebug::QmlDebugConnection *m_connection;
|
||||
QmlDebugConnection *m_connection;
|
||||
int m_requestId;
|
||||
qreal m_slowDownFactor;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSInspector
|
||||
} // namespace QmlDebug
|
||||
|
||||
#endif // QMLTOOLSCLIENT_H
|
@@ -18,6 +18,7 @@ Alternatively, this plugin may be used under the terms of the GNU Lesser General
|
||||
<dependency name=\"Core\" version=\"$$QTCREATOR_VERSION\"/>
|
||||
<dependency name=\"Find\" version=\"$$QTCREATOR_VERSION\"/>
|
||||
<dependency name=\"CppTools\" version=\"$$QTCREATOR_VERSION\"/>
|
||||
<dependency name=\"QmlJSTools\" version=\"$$QTCREATOR_VERSION\"/>
|
||||
<!-- Debugger plugin adds items to the editor\'s context menu -->
|
||||
<dependency name=\"CppEditor\" version=\"$$QTCREATOR_VERSION\" type=\"optional\"/>
|
||||
</dependencyList>
|
||||
|
@@ -74,6 +74,8 @@ CommonOptionsPageWidget::CommonOptionsPageWidget
|
||||
m_ui.checkBoxSwitchModeOnExit);
|
||||
m_group->insert(dc->action(RaiseOnInterrupt),
|
||||
m_ui.checkBoxBringToForegroundOnInterrrupt);
|
||||
m_group->insert(dc->action(ShowQmlObjectTree),
|
||||
m_ui.checkBoxShowQmlObjectTree);
|
||||
m_group->insert(dc->action(FontSizeFollowsEditor),
|
||||
m_ui.checkBoxFontSizeFollowsEditor);
|
||||
m_group->insert(dc->action(AutoDerefPointers), 0);
|
||||
@@ -123,6 +125,7 @@ QString CommonOptionsPageWidget::searchKeyWords() const
|
||||
<< sep << m_ui.checkBoxSwitchModeOnExit->text()
|
||||
<< sep << m_ui.labelMaximalStackDepth->text()
|
||||
<< sep << m_ui.checkBoxBringToForegroundOnInterrrupt->text()
|
||||
<< sep << m_ui.checkBoxShowQmlObjectTree->text()
|
||||
;
|
||||
rc.remove(QLatin1Char('&'));
|
||||
return rc;
|
||||
|
@@ -120,7 +120,14 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="checkBoxBringToForegroundOnInterrrupt">
|
||||
<property name="text">
|
||||
<string>Bring Qt Creator to foreground when application interrupts</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QCheckBox" name="checkBoxRegisterForPostMortem">
|
||||
<property name="toolTip">
|
||||
<string>Register Qt Creator for debugging crashed applications.</string>
|
||||
@@ -130,10 +137,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="checkBoxBringToForegroundOnInterrrupt">
|
||||
<item row="3" column="1">
|
||||
<widget class="QCheckBox" name="checkBoxShowQmlObjectTree">
|
||||
<property name="toolTip">
|
||||
<string>Show QML object tree in Locals & Expressions when connected and not stepping.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Bring Qt Creator to foreground when application interrupts</string>
|
||||
<string>Show QML object tree</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@@ -72,7 +72,8 @@ HEADERS += \
|
||||
qtmessagelogview.h \
|
||||
qtmessagelogproxymodel.h \
|
||||
qtmessagelogitemdelegate.h \
|
||||
qtmessageloghandler.h
|
||||
qtmessageloghandler.h \
|
||||
localsandwatcherswindow.h
|
||||
|
||||
SOURCES += \
|
||||
basewindow.cpp \
|
||||
@@ -123,7 +124,8 @@ SOURCES += \
|
||||
qtmessagelogview.cpp \
|
||||
qtmessagelogitemdelegate.cpp \
|
||||
qtmessageloghandler.cpp \
|
||||
qtmessagelogeditor.cpp
|
||||
qtmessagelogeditor.cpp \
|
||||
localsandwatcherswindow.cpp
|
||||
|
||||
FORMS += attachexternaldialog.ui \
|
||||
attachcoredialog.ui \
|
||||
|
@@ -8,6 +8,7 @@ QtcPlugin {
|
||||
Depends { name: "qt"; submodules: ['widgets', 'network', 'script'] }
|
||||
Depends { name: "Core" }
|
||||
Depends { name: "CppTools" }
|
||||
Depends { name: "QmlJSTools" }
|
||||
Depends { name: "Find" }
|
||||
Depends { name: "ProjectExplorer" }
|
||||
Depends { name: "TextEditor" }
|
||||
@@ -75,6 +76,8 @@ QtcPlugin {
|
||||
"disassemblerlines.cpp",
|
||||
"disassemblerlines.h",
|
||||
"dumperoptionpage.ui",
|
||||
"localsandwatcherswindow.cpp",
|
||||
"localsandwatcherswindow.h",
|
||||
"logwindow.cpp",
|
||||
"logwindow.h",
|
||||
"memoryagent.cpp",
|
||||
@@ -243,6 +246,12 @@ QtcPlugin {
|
||||
"qml/qscriptdebuggerclient.cpp",
|
||||
"qml/qmlv8debuggerclient.cpp",
|
||||
"qml/interactiveinterpreter.cpp",
|
||||
"qml/qmlinspectoradapter.cpp",
|
||||
"qml/qmlinspectoradapter.h",
|
||||
"qml/qmlinspectoragent.cpp",
|
||||
"qml/qmlinspectoragent.h",
|
||||
"qml/qmllivetextpreview.cpp",
|
||||
"qml/qmllivetextpreview.h",
|
||||
"script/scriptengine.cpp",
|
||||
"script/scriptengine.h",
|
||||
"shared/backtrace.cpp",
|
||||
|
@@ -36,5 +36,9 @@
|
||||
<file>images/log.png</file>
|
||||
<file>images/prompt.png</file>
|
||||
<file>images/warning.png</file>
|
||||
<file>images/qml/zoom.png</file>
|
||||
<file>images/qml/select.png</file>
|
||||
<file>images/qml/app-on-top.png</file>
|
||||
<file>images/qml/apply-on-save.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
@@ -3,6 +3,7 @@ include(../../plugins/cpptools/cpptools.pri)
|
||||
include(../../plugins/find/find.pri)
|
||||
include(../../plugins/projectexplorer/projectexplorer.pri)
|
||||
include(../../plugins/texteditor/texteditor.pri)
|
||||
include(../../plugins/qmljstools/qmljstools.pri)
|
||||
include(../../libs/cplusplus/cplusplus.pri)
|
||||
include(../../libs/utils/utils.pri)
|
||||
include(../../libs/symbianutils/symbianutils.pri)
|
||||
|
@@ -549,6 +549,30 @@ DebuggerSettings::DebuggerSettings(QSettings *settings)
|
||||
item->setSettingsKey(debugModeGroup, QLatin1String("WatchdogTimeout"));
|
||||
item->setDefaultValue(20);
|
||||
insertItem(GdbWatchdogTimeout, item);
|
||||
|
||||
//
|
||||
// QML Tools
|
||||
//
|
||||
item = new SavedAction(this);
|
||||
item->setSettingsKey(debugModeGroup, QLatin1String("ShowQmlObjectTree"));
|
||||
item->setDefaultValue(true);
|
||||
insertItem(ShowQmlObjectTree, item);
|
||||
|
||||
item = new SavedAction(this);
|
||||
item->setSettingsKey("QML.Inspector", QLatin1String("QmlInspector.ShowAppOnTop"));
|
||||
item->setText(tr("Show Application On Top"));
|
||||
item->setCheckable(true);
|
||||
item->setDefaultValue(false);
|
||||
item->setIcon(QIcon(QLatin1String(":/debugger/images/qml/app-on-top.png")));
|
||||
insertItem(ShowAppOnTop, item);
|
||||
|
||||
item = new SavedAction(this);
|
||||
item->setSettingsKey("QML.Inspector", QLatin1String("QmlInspector.FromQml"));
|
||||
item->setText(tr("Apply Changes on Save"));
|
||||
item->setCheckable(true);
|
||||
item->setDefaultValue(false);
|
||||
item->setIcon(QIcon(QLatin1String(":/debugger/images/qml/apply-on-save.png")));
|
||||
insertItem(QmlUpdateOnSave, item);
|
||||
}
|
||||
|
||||
DebuggerSettings::~DebuggerSettings()
|
||||
|
@@ -169,7 +169,12 @@ enum DebuggerActionCode
|
||||
AlwaysAdjustThreadsColumnWidths,
|
||||
|
||||
// Modules
|
||||
AlwaysAdjustModulesColumnWidths
|
||||
AlwaysAdjustModulesColumnWidths,
|
||||
|
||||
// QML Tools
|
||||
ShowQmlObjectTree,
|
||||
ShowAppOnTop,
|
||||
QmlUpdateOnSave
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
@@ -52,7 +52,7 @@ const char G_MANUAL_REMOTE[] = "Debugger.Group.Manual.Remote";
|
||||
const char G_AUTOMATIC_REMOTE[] = "Debugger.Group.Automatic.Remote";
|
||||
const char G_START_QML[] = "Debugger.Group.Start.Qml";
|
||||
|
||||
// Common actions (accessed by QML inspector)
|
||||
// Common actions
|
||||
const char INTERRUPT[] = "Debugger.Interrupt";
|
||||
const char CONTINUE[] = "Debugger.Continue";
|
||||
const char STOP[] = "Debugger.Stop";
|
||||
@@ -63,6 +63,8 @@ const char STEPOUT[] = "Debugger.StepOut";
|
||||
const char NEXT[] = "Debugger.NextLine";
|
||||
const char REVERSE[] = "Debugger.ReverseDirection";
|
||||
const char OPERATE_BY_INSTRUCTION[] = "Debugger.OperateByInstruction";
|
||||
const char QML_SELECTTOOL[] = "Debugger.QmlSelectTool";
|
||||
const char QML_ZOOMTOOL[] = "Debugger.QmlZoomTool";
|
||||
|
||||
// DebuggerMainWindow dock widget names
|
||||
const char DOCKWIDGET_BREAK[] = "Debugger.Docks.Break";
|
||||
|
@@ -513,6 +513,14 @@ QAbstractItemModel *DebuggerEngine::returnModel() const
|
||||
return model;
|
||||
}
|
||||
|
||||
QAbstractItemModel *DebuggerEngine::inspectorModel() const
|
||||
{
|
||||
QAbstractItemModel *model = watchHandler()->model(InspectWatch);
|
||||
if (model->objectName().isEmpty()) // Make debugging easier.
|
||||
model->setObjectName(objectName() + QLatin1String("InspectorModel"));
|
||||
return model;
|
||||
}
|
||||
|
||||
QAbstractItemModel *DebuggerEngine::toolTipsModel() const
|
||||
{
|
||||
QAbstractItemModel *model = watchHandler()->model(TooltipsWatch);
|
||||
|
@@ -75,6 +75,7 @@ class SourceFilesHandler;
|
||||
class ThreadsHandler;
|
||||
class WatchHandler;
|
||||
class BreakpointParameters;
|
||||
class QmlAdapter;
|
||||
class QmlCppEngine;
|
||||
class DebuggerToolTipContext;
|
||||
class MemoryMarkup;
|
||||
@@ -231,6 +232,7 @@ public:
|
||||
virtual QAbstractItemModel *localsModel() const;
|
||||
virtual QAbstractItemModel *watchersModel() const;
|
||||
virtual QAbstractItemModel *returnModel() const;
|
||||
virtual QAbstractItemModel *inspectorModel() const;
|
||||
virtual QAbstractItemModel *toolTipsModel() const;
|
||||
virtual QAbstractItemModel *sourceFilesModel() const;
|
||||
virtual QAbstractItemModel *qtMessageLogModel() const;
|
||||
@@ -408,7 +410,7 @@ private:
|
||||
// Wrapper engine needs access to state of its subengines.
|
||||
friend class Internal::QmlCppEngine;
|
||||
friend class Internal::DebuggerPluginPrivate;
|
||||
friend class QmlAdapter;
|
||||
friend class Internal::QmlAdapter;
|
||||
|
||||
virtual void setState(DebuggerState state, bool forced = false);
|
||||
|
||||
|
@@ -62,6 +62,7 @@
|
||||
#include "watchwindow.h"
|
||||
#include "watchutils.h"
|
||||
#include "debuggertooltipmanager.h"
|
||||
#include "localsandwatcherswindow.h"
|
||||
|
||||
#include "snapshothandler.h"
|
||||
#include "threadshandler.h"
|
||||
@@ -1119,6 +1120,10 @@ public slots:
|
||||
void attachedToProcess(const QString &channel, const QString &sysroot,
|
||||
const QString &remoteCommandLine, const QString &remoteExecutable);
|
||||
|
||||
void updateQmlActions() {
|
||||
action(QmlUpdateOnSave)->setEnabled(boolSetting(ShowQmlObjectTree));
|
||||
}
|
||||
|
||||
public:
|
||||
DebuggerMainWindow *m_mainWindow;
|
||||
DebuggerRunControlFactory *m_debuggerRunControlFactory;
|
||||
@@ -1177,6 +1182,7 @@ public:
|
||||
WatchWindow *m_returnWindow;
|
||||
WatchWindow *m_localsWindow;
|
||||
WatchWindow *m_watchersWindow;
|
||||
WatchWindow *m_inspectorWindow;
|
||||
BaseWindow *m_registerWindow;
|
||||
BaseWindow *m_modulesWindow;
|
||||
BaseWindow *m_snapshotWindow;
|
||||
@@ -1184,6 +1190,7 @@ public:
|
||||
BaseWindow *m_stackWindow;
|
||||
BaseWindow *m_threadsWindow;
|
||||
LogWindow *m_logWindow;
|
||||
LocalsAndWatchersWindow *m_localsAndWatchersWindow;
|
||||
|
||||
bool m_busy;
|
||||
QString m_lastPermanentStatusMessage;
|
||||
@@ -1230,6 +1237,7 @@ DebuggerPluginPrivate::DebuggerPluginPrivate(DebuggerPlugin *plugin) :
|
||||
m_returnWindow = 0;
|
||||
m_localsWindow = 0;
|
||||
m_watchersWindow = 0;
|
||||
m_inspectorWindow = 0;
|
||||
m_registerWindow = 0;
|
||||
m_modulesWindow = 0;
|
||||
m_snapshotWindow = 0;
|
||||
@@ -1237,6 +1245,7 @@ DebuggerPluginPrivate::DebuggerPluginPrivate(DebuggerPlugin *plugin) :
|
||||
m_stackWindow = 0;
|
||||
m_threadsWindow = 0;
|
||||
m_logWindow = 0;
|
||||
m_localsAndWatchersWindow = 0;
|
||||
m_qtMessageLogWindow = 0;
|
||||
|
||||
m_mainWindow = 0;
|
||||
@@ -2130,6 +2139,7 @@ void DebuggerPluginPrivate::connectEngine(DebuggerEngine *engine)
|
||||
//m_threadBox->setModel(engine->threadsModel());
|
||||
//m_threadBox->setModelColumn(ThreadData::ComboNameColumn);
|
||||
m_watchersWindow->setModel(engine->watchersModel());
|
||||
m_inspectorWindow->setModel(engine->inspectorModel());
|
||||
m_qtMessageLogWindow->setModel(engine->qtMessageLogModel());
|
||||
|
||||
engine->watchHandler()->rebuildModel();
|
||||
@@ -2162,6 +2172,7 @@ void DebuggerPluginPrivate::fontSettingsChanged
|
||||
changeFontSize(m_stackWindow, size);
|
||||
changeFontSize(m_threadsWindow, size);
|
||||
changeFontSize(m_watchersWindow, size);
|
||||
changeFontSize(m_inspectorWindow, size);
|
||||
}
|
||||
|
||||
void DebuggerPluginPrivate::cleanupViews()
|
||||
@@ -2261,7 +2272,7 @@ void DebuggerPluginPrivate::updateWatchersWindow()
|
||||
m_watchersWindow->setVisible(
|
||||
m_watchersWindow->model()->rowCount(QModelIndex()) > 0);
|
||||
m_returnWindow->setVisible(
|
||||
m_returnWindow->model()->rowCount(QModelIndex()) > 0);
|
||||
m_returnWindow->model()->rowCount(QModelIndex()) > 0);
|
||||
}
|
||||
|
||||
void DebuggerPluginPrivate::updateState(DebuggerEngine *engine)
|
||||
@@ -2305,6 +2316,7 @@ void DebuggerPluginPrivate::updateState(DebuggerEngine *engine)
|
||||
m_debugWithoutDeployAction->setEnabled(false);
|
||||
m_visibleStartAction->setAction(m_continueAction);
|
||||
m_hiddenStopAction->setAction(m_exitAction);
|
||||
m_localsAndWatchersWindow->setShowLocals(true);
|
||||
} else if (state == InferiorRunOk) {
|
||||
// Shift-F5 interrupts. It is also "interruptible".
|
||||
m_interruptAction->setEnabled(true);
|
||||
@@ -2314,6 +2326,7 @@ void DebuggerPluginPrivate::updateState(DebuggerEngine *engine)
|
||||
m_debugWithoutDeployAction->setEnabled(false);
|
||||
m_visibleStartAction->setAction(m_interruptAction);
|
||||
m_hiddenStopAction->setAction(m_interruptAction);
|
||||
m_localsAndWatchersWindow->setShowLocals(false);
|
||||
} else if (state == DebuggerFinished) {
|
||||
// We don't want to do anything anymore.
|
||||
m_interruptAction->setEnabled(false);
|
||||
@@ -2403,7 +2416,6 @@ void DebuggerPluginPrivate::updateState(DebuggerEngine *engine)
|
||||
|| state == DebuggerFinished
|
||||
|| state == InferiorUnrunnable;
|
||||
setBusyCursor(!notbusy);
|
||||
|
||||
}
|
||||
|
||||
void DebuggerPluginPrivate::updateDebugActions()
|
||||
@@ -2927,6 +2939,8 @@ void DebuggerPluginPrivate::extensionsInitialized()
|
||||
m_localsWindow->setObjectName(QLatin1String("CppDebugLocals"));
|
||||
m_watchersWindow = new WatchWindow(WatchTreeView::WatchersType);
|
||||
m_watchersWindow->setObjectName(QLatin1String("CppDebugWatchers"));
|
||||
m_inspectorWindow = new WatchWindow(WatchTreeView::InspectType);
|
||||
m_inspectorWindow->setObjectName(QLatin1String("Inspector"));
|
||||
|
||||
// Snapshot
|
||||
m_snapshotHandler = new SnapshotHandler;
|
||||
@@ -3018,6 +3032,22 @@ void DebuggerPluginPrivate::extensionsInitialized()
|
||||
connect(action(OperateByInstruction), SIGNAL(triggered(bool)),
|
||||
SLOT(handleOperateByInstructionTriggered(bool)));
|
||||
|
||||
QAction *qmlSelectDummyAction = new QAction(tr("Select"), this);
|
||||
qmlSelectDummyAction->setCheckable(true);
|
||||
qmlSelectDummyAction->setIcon(QIcon(_(":/debugger/images/qml/select.png")));
|
||||
qmlSelectDummyAction->setEnabled(false);
|
||||
Core::Command *qmlSelectCommand
|
||||
= am->registerAction(qmlSelectDummyAction, QML_SELECTTOOL,
|
||||
globalcontext);
|
||||
|
||||
QAction *qmlZoomDummyAction = new QAction(tr("Zoom"), this);
|
||||
qmlZoomDummyAction->setCheckable(true);
|
||||
qmlZoomDummyAction->setIcon(QIcon(_(":/debugger/images/qml/zoom.png")));
|
||||
qmlZoomDummyAction->setEnabled(false);
|
||||
Core::Command *qmlZoomCommand
|
||||
= am->registerAction(qmlZoomDummyAction, QML_ZOOMTOOL,
|
||||
globalcontext);
|
||||
|
||||
ActionContainer *debugMenu =
|
||||
am->actionContainer(ProjectExplorer::Constants::M_DEBUG);
|
||||
|
||||
@@ -3044,17 +3074,13 @@ void DebuggerPluginPrivate::extensionsInitialized()
|
||||
m_mainWindow->createDockWidget(CppLanguage, m_stackWindow);
|
||||
m_mainWindow->createDockWidget(CppLanguage, m_threadsWindow);
|
||||
|
||||
QSplitter *localsAndWatchers = new MiniSplitter(Qt::Vertical);
|
||||
localsAndWatchers->setObjectName(QLatin1String(DOCKWIDGET_WATCHERS));
|
||||
localsAndWatchers->setWindowTitle(m_localsWindow->windowTitle());
|
||||
localsAndWatchers->addWidget(m_localsWindow);
|
||||
localsAndWatchers->addWidget(m_returnWindow);
|
||||
localsAndWatchers->addWidget(m_watchersWindow);
|
||||
localsAndWatchers->setStretchFactor(0, 3);
|
||||
localsAndWatchers->setStretchFactor(1, 1);
|
||||
localsAndWatchers->setStretchFactor(2, 1);
|
||||
m_localsAndWatchersWindow = new LocalsAndWatchersWindow(
|
||||
m_localsWindow, m_inspectorWindow, m_returnWindow,
|
||||
m_watchersWindow);
|
||||
m_localsAndWatchersWindow->setObjectName(QLatin1String(DOCKWIDGET_WATCHERS));
|
||||
m_localsAndWatchersWindow->setWindowTitle(m_localsWindow->windowTitle());
|
||||
|
||||
dock = m_mainWindow->createDockWidget(CppLanguage, localsAndWatchers);
|
||||
dock = m_mainWindow->createDockWidget(CppLanguage, m_localsAndWatchersWindow);
|
||||
dock->setProperty(DOCKWIDGET_DEFAULT_AREA, Qt::RightDockWidgetArea);
|
||||
|
||||
m_mainWindow->addStagedMenuEntries();
|
||||
@@ -3443,6 +3469,11 @@ void DebuggerPluginPrivate::extensionsInitialized()
|
||||
connect(action(SettingsDialog), SIGNAL(triggered()),
|
||||
SLOT(showSettingsDialog()));
|
||||
|
||||
// QML Actions
|
||||
connect(action(ShowQmlObjectTree), SIGNAL(valueChanged(QVariant)),
|
||||
SLOT(updateQmlActions()));
|
||||
updateQmlActions();
|
||||
|
||||
// Toolbar
|
||||
QWidget *toolbarContainer = new QWidget;
|
||||
|
||||
@@ -3472,6 +3503,19 @@ void DebuggerPluginPrivate::extensionsInitialized()
|
||||
hbox->addSpacerItem(new QSpacerItem(4, 0));
|
||||
|
||||
m_mainWindow->setToolBar(CppLanguage, toolbarContainer);
|
||||
|
||||
QWidget *qmlToolbar = new QWidget;
|
||||
hbox = new QHBoxLayout(qmlToolbar);
|
||||
hbox->setMargin(0);
|
||||
hbox->setSpacing(0);
|
||||
hbox->addWidget(toolButton(action(QmlUpdateOnSave)));
|
||||
hbox->addWidget(toolButton(action(ShowAppOnTop)));
|
||||
hbox->addWidget(new Utils::StyledSeparator);
|
||||
hbox->addWidget(toolButton(qmlSelectCommand->action()));
|
||||
hbox->addWidget(toolButton(qmlZoomCommand->action()));
|
||||
hbox->addWidget(new Utils::StyledSeparator);
|
||||
m_mainWindow->setToolBar(QmlLanguage, qmlToolbar);
|
||||
|
||||
m_mainWindow->setToolBar(AnyLanguage, m_statusLabel);
|
||||
|
||||
connect(action(EnableReverseDebugging),
|
||||
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
41
src/plugins/debugger/localsandwatcherswindow.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
#include "localsandwatcherswindow.h"
|
||||
#include <QVBoxLayout>
|
||||
#include <QSplitter>
|
||||
#include <QStackedWidget>
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
LocalsAndWatchersWindow::LocalsAndWatchersWindow(
|
||||
QWidget *locals, QWidget *inspector, QWidget *returnWidget,
|
||||
QWidget *watchers, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
layout->setMargin(0);
|
||||
layout->setSpacing(0);
|
||||
|
||||
m_splitter = new QSplitter(Qt::Vertical);
|
||||
layout->addWidget(m_splitter);
|
||||
|
||||
m_localsAndInspector = new QStackedWidget();
|
||||
m_localsAndInspector->addWidget(locals);
|
||||
m_localsAndInspector->addWidget(inspector);
|
||||
m_localsAndInspector->setCurrentWidget(inspector);
|
||||
|
||||
m_splitter->addWidget(m_localsAndInspector);
|
||||
m_splitter->addWidget(returnWidget);
|
||||
m_splitter->addWidget(watchers);
|
||||
|
||||
m_splitter->setStretchFactor(0, 3);
|
||||
m_splitter->setStretchFactor(2, 1);
|
||||
m_splitter->setStretchFactor(3, 1);
|
||||
}
|
||||
|
||||
void LocalsAndWatchersWindow::setShowLocals(bool showLocals)
|
||||
{
|
||||
m_localsAndInspector->setCurrentIndex(showLocals ? 0 : 1);
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Debugger
|
32
src/plugins/debugger/localsandwatcherswindow.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef LOCALSANDWATCHERSWIDGET_H
|
||||
#define LOCALSANDWATCHERSWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QSplitter;
|
||||
class QStackedWidget;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
class LocalsAndWatchersWindow : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit LocalsAndWatchersWindow(
|
||||
QWidget *locals, QWidget *inspector,
|
||||
QWidget *returnWidget, QWidget *watchers, QWidget *parent = 0);
|
||||
|
||||
void setShowLocals(bool showLocals);
|
||||
|
||||
private:
|
||||
QSplitter *m_splitter;
|
||||
QStackedWidget *m_localsAndInspector;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Debugger
|
||||
|
||||
#endif // LOCALSANDWATCHERSWIDGET_H
|
@@ -8,7 +8,10 @@ HEADERS += \
|
||||
$$PWD/qscriptdebuggerclient.h \
|
||||
$$PWD/qmlv8debuggerclient.h \
|
||||
$$PWD/interactiveinterpreter.h \
|
||||
$$PWD/qmlv8debuggerclientconstants.h
|
||||
$$PWD/qmlv8debuggerclientconstants.h \
|
||||
$$PWD/qmlinspectoragent.h \
|
||||
$$PWD/qmllivetextpreview.h \
|
||||
$$PWD/qmlinspectoradapter.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/qmlengine.cpp \
|
||||
@@ -17,4 +20,7 @@ SOURCES += \
|
||||
$$PWD/qmlcppengine.cpp \
|
||||
$$PWD/qscriptdebuggerclient.cpp \
|
||||
$$PWD/qmlv8debuggerclient.cpp \
|
||||
$$PWD/interactiveinterpreter.cpp
|
||||
$$PWD/interactiveinterpreter.cpp \
|
||||
$$PWD/qmlinspectoragent.cpp \
|
||||
$$PWD/qmllivetextpreview.cpp \
|
||||
$$PWD/qmlinspectoradapter.cpp
|
||||
|
@@ -32,116 +32,80 @@
|
||||
|
||||
#include "qmladapter.h"
|
||||
|
||||
#include "qscriptdebuggerclient.h"
|
||||
#include "qmlv8debuggerclient.h"
|
||||
|
||||
#include "qmlengine.h"
|
||||
#include "qmlv8debuggerclient.h"
|
||||
#include "qscriptdebuggerclient.h"
|
||||
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
#include <qmldebug/qdebugmessageclient.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <qmldebug/baseenginedebugclient.h>
|
||||
#include <qmldebug/qdebugmessageclient.h>
|
||||
|
||||
#include <QTimer>
|
||||
#include <QDebug>
|
||||
#include <QWeakPointer>
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
class QmlAdapterPrivate
|
||||
{
|
||||
public:
|
||||
explicit QmlAdapterPrivate(DebuggerEngine *engine)
|
||||
: m_engine(engine)
|
||||
, m_qmlClient(0)
|
||||
, m_engineDebugClient(0)
|
||||
, m_conn(0)
|
||||
, m_currentSelectedDebugId(-1)
|
||||
, m_msgClient(0)
|
||||
{
|
||||
m_connectionTimer.setInterval(4000);
|
||||
m_connectionTimer.setSingleShot(true);
|
||||
}
|
||||
|
||||
QWeakPointer<DebuggerEngine> m_engine;
|
||||
BaseQmlDebuggerClient *m_qmlClient;
|
||||
BaseEngineDebugClient *m_engineDebugClient;
|
||||
QTimer m_connectionTimer;
|
||||
QmlDebugConnection *m_conn;
|
||||
QHash<QString, BaseQmlDebuggerClient*> debugClients;
|
||||
int m_currentSelectedDebugId;
|
||||
QString m_currentSelectedDebugName;
|
||||
QDebugMessageClient *m_msgClient;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
||||
QmlAdapter::QmlAdapter(DebuggerEngine *engine, QObject *parent)
|
||||
: QObject(parent), d(new Internal::QmlAdapterPrivate(engine))
|
||||
: QObject(parent)
|
||||
, m_engine(engine)
|
||||
, m_qmlClient(0)
|
||||
, m_conn(0)
|
||||
, m_msgClient(0)
|
||||
{
|
||||
connect(&d->m_connectionTimer, SIGNAL(timeout()), SLOT(checkConnectionState()));
|
||||
d->m_conn = new QmlDebugConnection(this);
|
||||
connect(d->m_conn, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
|
||||
m_connectionTimer.setInterval(4000);
|
||||
m_connectionTimer.setSingleShot(true);
|
||||
connect(&m_connectionTimer, SIGNAL(timeout()), SLOT(checkConnectionState()));
|
||||
|
||||
m_conn = new QmlDebugConnection(this);
|
||||
connect(m_conn, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
|
||||
SLOT(connectionStateChanged()));
|
||||
connect(d->m_conn, SIGNAL(error(QAbstractSocket::SocketError)),
|
||||
connect(m_conn, SIGNAL(error(QAbstractSocket::SocketError)),
|
||||
SLOT(connectionErrorOccurred(QAbstractSocket::SocketError)));
|
||||
|
||||
ExtensionSystem::PluginManager *pluginManager =
|
||||
ExtensionSystem::PluginManager::instance();
|
||||
pluginManager->addObject(this);
|
||||
|
||||
createDebuggerClients();
|
||||
d->m_msgClient = new QDebugMessageClient(d->m_conn);
|
||||
connect(d->m_msgClient, SIGNAL(newStatus(QmlDebugClient::Status)),
|
||||
m_msgClient = new QDebugMessageClient(m_conn);
|
||||
connect(m_msgClient, SIGNAL(newStatus(QmlDebugClient::Status)),
|
||||
this, SLOT(clientStatusChanged(QmlDebugClient::Status)));
|
||||
|
||||
}
|
||||
|
||||
QmlAdapter::~QmlAdapter()
|
||||
{
|
||||
ExtensionSystem::PluginManager *pluginManager =
|
||||
ExtensionSystem::PluginManager::instance();
|
||||
|
||||
if (pluginManager->allObjects().contains(this))
|
||||
pluginManager->removeObject(this);
|
||||
delete d;
|
||||
}
|
||||
|
||||
void QmlAdapter::beginConnectionTcp(const QString &address, quint16 port)
|
||||
{
|
||||
if (d->m_engine.isNull()
|
||||
|| (d->m_conn && d->m_conn->state() != QAbstractSocket::UnconnectedState))
|
||||
if (m_engine.isNull()
|
||||
|| (m_conn && m_conn->state() != QAbstractSocket::UnconnectedState))
|
||||
return;
|
||||
|
||||
showConnectionStatusMessage(tr("Connecting to debug server %1:%2").arg(address).arg(
|
||||
QString::number(port)));
|
||||
d->m_conn->connectToHost(address, port);
|
||||
m_conn->connectToHost(address, port);
|
||||
|
||||
//A timeout to check the connection state
|
||||
d->m_connectionTimer.start();
|
||||
m_connectionTimer.start();
|
||||
}
|
||||
|
||||
void QmlAdapter::beginConnectionOst(const QString &channel)
|
||||
{
|
||||
if (d->m_engine.isNull()
|
||||
|| (d->m_conn && d->m_conn->state() != QAbstractSocket::UnconnectedState))
|
||||
if (m_engine.isNull()
|
||||
|| (m_conn && m_conn->state() != QAbstractSocket::UnconnectedState))
|
||||
return;
|
||||
|
||||
showConnectionStatusMessage(tr("Connecting to debug server on %1").arg(channel));
|
||||
d->m_conn->connectToOst(channel);
|
||||
m_conn->connectToOst(channel);
|
||||
|
||||
//A timeout to check the connection state
|
||||
d->m_connectionTimer.start();
|
||||
m_connectionTimer.start();
|
||||
}
|
||||
|
||||
void QmlAdapter::closeConnection()
|
||||
{
|
||||
if (d->m_connectionTimer.isActive()) {
|
||||
d->m_connectionTimer.stop();
|
||||
if (m_connectionTimer.isActive()) {
|
||||
m_connectionTimer.stop();
|
||||
} else {
|
||||
if (d->m_conn) {
|
||||
d->m_conn->close();
|
||||
if (m_conn) {
|
||||
m_conn->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -149,13 +113,13 @@ void QmlAdapter::closeConnection()
|
||||
void QmlAdapter::connectionErrorOccurred(QAbstractSocket::SocketError socketError)
|
||||
{
|
||||
showConnectionStatusMessage(tr("Error: (%1) %2", "%1=error code, %2=error message")
|
||||
.arg(socketError).arg(d->m_conn->errorString()));
|
||||
.arg(socketError).arg(m_conn->errorString()));
|
||||
|
||||
// this is only an error if we are already connected and something goes wrong.
|
||||
if (isConnected()) {
|
||||
emit connectionError(socketError);
|
||||
} else {
|
||||
d->m_connectionTimer.stop();
|
||||
m_connectionTimer.stop();
|
||||
emit connectionStartupFailed();
|
||||
}
|
||||
}
|
||||
@@ -179,13 +143,13 @@ void QmlAdapter::debugClientStatusChanged(QmlDebugClient::Status status)
|
||||
QmlDebugClient *client = qobject_cast<QmlDebugClient*>(sender());
|
||||
QTC_ASSERT(client, return);
|
||||
|
||||
d->m_qmlClient = qobject_cast<Internal::BaseQmlDebuggerClient *>(client);
|
||||
d->m_qmlClient->startSession();
|
||||
m_qmlClient = qobject_cast<Internal::BaseQmlDebuggerClient *>(client);
|
||||
m_qmlClient->startSession();
|
||||
}
|
||||
|
||||
void QmlAdapter::connectionStateChanged()
|
||||
{
|
||||
switch (d->m_conn->state()) {
|
||||
switch (m_conn->state()) {
|
||||
case QAbstractSocket::UnconnectedState:
|
||||
{
|
||||
showConnectionStatusMessage(tr("disconnected.\n\n"));
|
||||
@@ -203,7 +167,7 @@ void QmlAdapter::connectionStateChanged()
|
||||
{
|
||||
showConnectionStatusMessage(tr("connected.\n"));
|
||||
|
||||
d->m_connectionTimer.stop();
|
||||
m_connectionTimer.stop();
|
||||
|
||||
//reloadEngines();
|
||||
emit connected();
|
||||
@@ -228,125 +192,83 @@ void QmlAdapter::checkConnectionState()
|
||||
|
||||
void QmlAdapter::createDebuggerClients()
|
||||
{
|
||||
|
||||
Internal::QScriptDebuggerClient *client1 = new Internal::QScriptDebuggerClient(d->m_conn);
|
||||
connect(client1, SIGNAL(newStatus(QmlDebugClient::Status)),
|
||||
Internal::QScriptDebuggerClient *debugClient1 = new Internal::QScriptDebuggerClient(m_conn);
|
||||
connect(debugClient1, SIGNAL(newStatus(QmlDebugClient::Status)),
|
||||
this, SLOT(clientStatusChanged(QmlDebugClient::Status)));
|
||||
connect(client1, SIGNAL(newStatus(QmlDebugClient::Status)),
|
||||
connect(debugClient1, SIGNAL(newStatus(QmlDebugClient::Status)),
|
||||
this, SLOT(debugClientStatusChanged(QmlDebugClient::Status)));
|
||||
|
||||
Internal::QmlV8DebuggerClient *client2 = new Internal::QmlV8DebuggerClient(d->m_conn);
|
||||
connect(client2, SIGNAL(newStatus(QmlDebugClient::Status)),
|
||||
Internal::QmlV8DebuggerClient *debugClient2 = new Internal::QmlV8DebuggerClient(m_conn);
|
||||
connect(debugClient2, SIGNAL(newStatus(QmlDebugClient::Status)),
|
||||
this, SLOT(clientStatusChanged(QmlDebugClient::Status)));
|
||||
connect(client2, SIGNAL(newStatus(QmlDebugClient::Status)),
|
||||
connect(debugClient2, SIGNAL(newStatus(QmlDebugClient::Status)),
|
||||
this, SLOT(debugClientStatusChanged(QmlDebugClient::Status)));
|
||||
|
||||
d->debugClients.insert(client1->name(),client1);
|
||||
d->debugClients.insert(client2->name(),client2);
|
||||
m_debugClients.insert(debugClient1->name(),debugClient1);
|
||||
m_debugClients.insert(debugClient2->name(),debugClient2);
|
||||
|
||||
|
||||
client1->setEngine((Internal::QmlEngine*)(d->m_engine.data()));
|
||||
client2->setEngine((Internal::QmlEngine*)(d->m_engine.data()));
|
||||
|
||||
//engine->startSuccessful(); // FIXME: AAA: port to new debugger states
|
||||
debugClient1->setEngine((Internal::QmlEngine*)(m_engine.data()));
|
||||
debugClient2->setEngine((Internal::QmlEngine*)(m_engine.data()));
|
||||
}
|
||||
|
||||
bool QmlAdapter::isConnected() const
|
||||
{
|
||||
return d->m_conn && d->m_qmlClient && d->m_conn->state() == QAbstractSocket::ConnectedState;
|
||||
return m_conn && m_qmlClient && m_conn->state() == QAbstractSocket::ConnectedState;
|
||||
}
|
||||
|
||||
QmlDebugConnection *QmlAdapter::connection() const
|
||||
{
|
||||
return d->m_conn;
|
||||
return m_conn;
|
||||
}
|
||||
|
||||
DebuggerEngine *QmlAdapter::debuggerEngine() const
|
||||
{
|
||||
return d->m_engine.data();
|
||||
return m_engine.data();
|
||||
}
|
||||
|
||||
void QmlAdapter::showConnectionStatusMessage(const QString &message)
|
||||
{
|
||||
if (!d->m_engine.isNull())
|
||||
d->m_engine.data()->showMessage(QLatin1String("QML Debugger: ") + message, LogStatus);
|
||||
if (!m_engine.isNull())
|
||||
m_engine.data()->showMessage(QLatin1String("QML Debugger: ") + message, LogStatus);
|
||||
}
|
||||
|
||||
void QmlAdapter::showConnectionErrorMessage(const QString &message)
|
||||
{
|
||||
if (!d->m_engine.isNull())
|
||||
d->m_engine.data()->showMessage(QLatin1String("QML Debugger: ") + message, LogError);
|
||||
if (!m_engine.isNull())
|
||||
m_engine.data()->showMessage(QLatin1String("QML Debugger: ") + message, LogError);
|
||||
}
|
||||
|
||||
bool QmlAdapter::disableJsDebugging(bool block)
|
||||
{
|
||||
if (d->m_engine.isNull())
|
||||
if (m_engine.isNull())
|
||||
return block;
|
||||
|
||||
bool isBlocked = d->m_engine.data()->state() == InferiorRunOk;
|
||||
bool isBlocked = m_engine.data()->state() == InferiorRunOk;
|
||||
|
||||
if (isBlocked == block)
|
||||
return block;
|
||||
|
||||
if (block) {
|
||||
d->m_engine.data()->continueInferior();
|
||||
} else {
|
||||
d->m_engine.data()->requestInterruptInferior();
|
||||
}
|
||||
if (block)
|
||||
m_engine.data()->continueInferior();
|
||||
else
|
||||
m_engine.data()->requestInterruptInferior();
|
||||
|
||||
return isBlocked;
|
||||
}
|
||||
|
||||
Internal::BaseQmlDebuggerClient *QmlAdapter::activeDebuggerClient()
|
||||
{
|
||||
return d->m_qmlClient;
|
||||
return m_qmlClient;
|
||||
}
|
||||
|
||||
QHash<QString, Internal::BaseQmlDebuggerClient*> QmlAdapter::debuggerClients()
|
||||
{
|
||||
return d->debugClients;
|
||||
}
|
||||
|
||||
BaseEngineDebugClient *QmlAdapter::engineDebugClient() const
|
||||
{
|
||||
return d->m_engineDebugClient;
|
||||
}
|
||||
|
||||
void QmlAdapter::setEngineDebugClient(BaseEngineDebugClient *client)
|
||||
{
|
||||
Internal::QmlEngine *engine =
|
||||
qobject_cast<Internal::QmlEngine *>(d->m_engine.data());
|
||||
if (engine && d->m_engineDebugClient)
|
||||
disconnect(d->m_engineDebugClient, SIGNAL(result(quint32,QVariant,QByteArray)),
|
||||
engine,
|
||||
SLOT(expressionEvaluated(quint32,QVariant)));
|
||||
d->m_engineDebugClient = client;
|
||||
if (engine && d->m_engineDebugClient)
|
||||
connect(d->m_engineDebugClient, SIGNAL(result(quint32,QVariant,QByteArray)),
|
||||
engine,
|
||||
SLOT(expressionEvaluated(quint32,QVariant)));
|
||||
return m_debugClients;
|
||||
}
|
||||
|
||||
QDebugMessageClient *QmlAdapter::messageClient() const
|
||||
{
|
||||
return d->m_msgClient;
|
||||
}
|
||||
|
||||
int QmlAdapter::currentSelectedDebugId() const
|
||||
{
|
||||
return d->m_currentSelectedDebugId;
|
||||
}
|
||||
|
||||
QString QmlAdapter::currentSelectedDisplayName() const
|
||||
{
|
||||
return d->m_currentSelectedDebugName;
|
||||
}
|
||||
|
||||
void QmlAdapter::setCurrentSelectedDebugInfo(int currentDebugId, const QString &displayName)
|
||||
{
|
||||
d->m_currentSelectedDebugId = currentDebugId;
|
||||
d->m_currentSelectedDebugName = displayName;
|
||||
emit selectionChanged();
|
||||
return m_msgClient;
|
||||
}
|
||||
|
||||
void QmlAdapter::logServiceStatusChange(const QString &service, float version,
|
||||
@@ -374,8 +296,9 @@ void QmlAdapter::logServiceStatusChange(const QString &service, float version,
|
||||
|
||||
void QmlAdapter::logServiceActivity(const QString &service, const QString &logMessage)
|
||||
{
|
||||
if (!d->m_engine.isNull())
|
||||
d->m_engine.data()->showMessage(service + QLatin1Char(' ') + logMessage, LogDebug);
|
||||
if (!m_engine.isNull())
|
||||
m_engine.data()->showMessage(service + QLatin1Char(' ') + logMessage, LogDebug);
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Debugger
|
||||
|
@@ -35,18 +35,21 @@
|
||||
|
||||
#include "debugger_global.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QAbstractSocket>
|
||||
#include <qmldebug/qmldebugclient.h>
|
||||
|
||||
#include <QAbstractSocket>
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
#include <QTimer>
|
||||
|
||||
using namespace QmlDebug;
|
||||
|
||||
namespace QmlDebug {
|
||||
class BaseEngineDebugClient;
|
||||
class QmlDebugConnection;
|
||||
class QDebugMessageClient;
|
||||
}
|
||||
|
||||
using namespace QmlDebug;
|
||||
|
||||
namespace Debugger {
|
||||
|
||||
class DebuggerEngine;
|
||||
@@ -54,9 +57,8 @@ class DebuggerEngine;
|
||||
namespace Internal {
|
||||
class BaseQmlDebuggerClient;
|
||||
class QmlAdapterPrivate;
|
||||
} // namespace Internal
|
||||
|
||||
class DEBUGGER_EXPORT QmlAdapter : public QObject
|
||||
class QmlAdapter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
@@ -79,14 +81,8 @@ public:
|
||||
QHash<QString, Internal::BaseQmlDebuggerClient*> debuggerClients();
|
||||
|
||||
BaseEngineDebugClient *engineDebugClient() const;
|
||||
void setEngineDebugClient(BaseEngineDebugClient *client);
|
||||
|
||||
QDebugMessageClient *messageClient() const;
|
||||
|
||||
int currentSelectedDebugId() const;
|
||||
QString currentSelectedDisplayName() const;
|
||||
void setCurrentSelectedDebugInfo(int debugId, const QString &displayName = QString());
|
||||
|
||||
public slots:
|
||||
void logServiceStatusChange(const QString &service, float version,
|
||||
QmlDebugClient::Status newStatus);
|
||||
@@ -98,7 +94,6 @@ signals:
|
||||
void connectionStartupFailed();
|
||||
void connectionError(QAbstractSocket::SocketError socketError);
|
||||
void serviceConnectionError(const QString serviceName);
|
||||
void selectionChanged();
|
||||
|
||||
private slots:
|
||||
void connectionErrorOccurred(QAbstractSocket::SocketError socketError);
|
||||
@@ -113,9 +108,15 @@ private:
|
||||
void showConnectionErrorMessage(const QString &message);
|
||||
|
||||
private:
|
||||
Internal::QmlAdapterPrivate *d;
|
||||
QPointer<DebuggerEngine> m_engine;
|
||||
BaseQmlDebuggerClient *m_qmlClient;
|
||||
QTimer m_connectionTimer;
|
||||
QmlDebugConnection *m_conn;
|
||||
QHash<QString, BaseQmlDebuggerClient*> m_debugClients;
|
||||
QDebugMessageClient *m_msgClient;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Debugger
|
||||
|
||||
#endif // QMLADAPTER_H
|
||||
|
@@ -37,6 +37,7 @@
|
||||
#include "stackhandler.h"
|
||||
#include "qmlengine.h"
|
||||
#include "qtmessageloghandler.h"
|
||||
#include "watchdata.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <utils/qtcassert.h>
|
||||
@@ -149,6 +150,8 @@ bool QmlCppEngine::setToolTipExpression(const QPoint & mousePos,
|
||||
void QmlCppEngine::updateWatchData(const WatchData &data,
|
||||
const WatchUpdateFlags &flags)
|
||||
{
|
||||
if (data.iname.startsWith("inspect."))
|
||||
d->m_qmlEngine->updateWatchData(data, flags);
|
||||
d->m_activeEngine->updateWatchData(data, flags);
|
||||
}
|
||||
|
||||
|
@@ -40,7 +40,7 @@ namespace Internal {
|
||||
|
||||
class QmlCppEnginePrivate;
|
||||
|
||||
class DEBUGGER_EXPORT QmlCppEngine : public DebuggerEngine
|
||||
class QmlCppEngine : public DebuggerEngine
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
@@ -32,8 +32,10 @@
|
||||
|
||||
#include "qmlengine.h"
|
||||
#include "qmladapter.h"
|
||||
#include "qmlinspectoradapter.h"
|
||||
#include "interactiveinterpreter.h"
|
||||
#include "baseqmldebuggerclient.h"
|
||||
#include "qmlinspectoragent.h"
|
||||
|
||||
#include "debuggerstartparameters.h"
|
||||
#include "debuggeractions.h"
|
||||
@@ -113,13 +115,13 @@ public:
|
||||
private:
|
||||
friend class QmlEngine;
|
||||
QmlAdapter m_adapter;
|
||||
QmlInspectorAdapter m_inspectorAdapter;
|
||||
ApplicationLauncher m_applicationLauncher;
|
||||
QTimer m_noDebugOutputTimer;
|
||||
QmlOutputParser m_outputParser;
|
||||
QHash<QString, QTextDocument*> m_sourceDocuments;
|
||||
QHash<QString, QWeakPointer<TextEditor::ITextEditor> > m_sourceEditors;
|
||||
InteractiveInterpreter m_interpreter;
|
||||
bool m_validContext;
|
||||
QHash<QString,BreakpointModelId> pendingBreakpoints;
|
||||
QList<quint32> queryIds;
|
||||
bool m_retryOnConnectFail;
|
||||
@@ -128,10 +130,11 @@ private:
|
||||
|
||||
QmlEnginePrivate::QmlEnginePrivate(QmlEngine *q)
|
||||
: m_adapter(q),
|
||||
m_validContext(false),
|
||||
m_inspectorAdapter(&m_adapter, q),
|
||||
m_retryOnConnectFail(false),
|
||||
m_automaticConnect(false)
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
class ASTWalker: public Visitor
|
||||
{
|
||||
@@ -326,14 +329,18 @@ QmlEngine::QmlEngine(const DebuggerStartParameters &startParameters,
|
||||
SLOT(updateCurrentContext()));
|
||||
connect(this->stackHandler(), SIGNAL(currentIndexChanged()),
|
||||
SLOT(updateCurrentContext()));
|
||||
connect(&d->m_adapter, SIGNAL(selectionChanged()),
|
||||
connect(&d->m_inspectorAdapter, SIGNAL(selectionChanged()),
|
||||
SLOT(updateCurrentContext()));
|
||||
connect(d->m_inspectorAdapter.agent(), SIGNAL(
|
||||
expressionResult(quint32,QVariant)),
|
||||
SLOT(expressionEvaluated(quint32,QVariant)));
|
||||
connect(d->m_adapter.messageClient(),
|
||||
SIGNAL(message(QtMsgType,QString,
|
||||
QmlDebug::QDebugContextInfo)),
|
||||
SLOT(appendDebugOutput(QtMsgType,QString,
|
||||
QmlDebug::QDebugContextInfo)));
|
||||
|
||||
|
||||
connect(&d->m_applicationLauncher,
|
||||
SIGNAL(processExited(int)),
|
||||
SLOT(disconnected()));
|
||||
@@ -1027,19 +1034,23 @@ void QmlEngine::updateWatchData(const WatchData &data,
|
||||
{
|
||||
// qDebug() << "UPDATE WATCH DATA" << data.toString();
|
||||
//watchHandler()->rebuildModel();
|
||||
showStatusMessage(tr("Stopped."), 5000);
|
||||
//showStatusMessage(tr("Stopped."), 5000);
|
||||
|
||||
if (!data.name.isEmpty() && d->m_adapter.activeDebuggerClient()) {
|
||||
if (data.isValueNeeded()) {
|
||||
d->m_adapter.activeDebuggerClient()->updateWatchData(data);
|
||||
}
|
||||
if (data.isChildrenNeeded()
|
||||
&& watchHandler()->isExpandedIName(data.iname)) {
|
||||
d->m_adapter.activeDebuggerClient()->expandObject(data.iname, data.id);
|
||||
if (data.iname.startsWith("inspect.")) {
|
||||
d->m_inspectorAdapter.agent()->updateWatchData(data);
|
||||
} else {
|
||||
if (!data.name.isEmpty() && d->m_adapter.activeDebuggerClient()) {
|
||||
if (data.isValueNeeded()) {
|
||||
d->m_adapter.activeDebuggerClient()->updateWatchData(data);
|
||||
}
|
||||
if (data.isChildrenNeeded()
|
||||
&& watchHandler()->isExpandedIName(data.iname)) {
|
||||
d->m_adapter.activeDebuggerClient()->expandObject(data.iname, data.id);
|
||||
}
|
||||
}
|
||||
synchronizeWatchers();
|
||||
}
|
||||
|
||||
synchronizeWatchers();
|
||||
|
||||
if (!data.isSomethingNeeded())
|
||||
watchHandler()->insertData(data);
|
||||
@@ -1111,8 +1122,7 @@ void QmlEngine::updateCurrentContext()
|
||||
{
|
||||
const QString context = state() == InferiorStopOk ?
|
||||
stackHandler()->currentFrame().function :
|
||||
d->m_adapter.currentSelectedDisplayName();
|
||||
d->m_validContext = !context.isEmpty();
|
||||
d->m_inspectorAdapter.currentSelectedDisplayName();
|
||||
showMessage(tr("Context: ").append(context), QtMessageLogStatus);
|
||||
}
|
||||
|
||||
@@ -1149,55 +1159,39 @@ void QmlEngine::executeDebuggerCommand(const QString &command, DebuggerLanguages
|
||||
}
|
||||
}
|
||||
|
||||
bool QmlEngine::evaluateScriptExpression(const QString& expression)
|
||||
bool QmlEngine::evaluateScriptExpression(const QString &expression)
|
||||
{
|
||||
bool didEvaluate = true;
|
||||
//Check if string is only white spaces
|
||||
if (!expression.trimmed().isEmpty()) {
|
||||
//Check for a valid context
|
||||
if (d->m_validContext) {
|
||||
//check if it can be evaluated
|
||||
if (canEvaluateScript(expression)) {
|
||||
//Evaluate expression based on engine state
|
||||
//When engine->state() == InferiorStopOk, the expression
|
||||
//is sent to V8DebugService. In all other cases, the
|
||||
//expression is evaluated by QDeclarativeEngine.
|
||||
if (state() != InferiorStopOk) {
|
||||
BaseEngineDebugClient *engineDebug =
|
||||
d->m_adapter.engineDebugClient();
|
||||
|
||||
int id = d->m_adapter.currentSelectedDebugId();
|
||||
if (engineDebug && id != -1) {
|
||||
quint32 queryId =
|
||||
engineDebug->queryExpressionResult(
|
||||
id, expression);
|
||||
if (queryId) {
|
||||
d->queryIds << queryId;
|
||||
} else {
|
||||
didEvaluate = false;
|
||||
qtMessageLogHandler()->
|
||||
appendItem(
|
||||
new QtMessageLogItem(
|
||||
qtMessageLogHandler()->root(),
|
||||
QtMessageLogHandler::ErrorType,
|
||||
_("Error evaluating expression.")));
|
||||
}
|
||||
}
|
||||
//check if it can be evaluated
|
||||
if (canEvaluateScript(expression)) {
|
||||
//Evaluate expression based on engine state
|
||||
//When engine->state() == InferiorStopOk, the expression
|
||||
//is sent to V8DebugService. In all other cases, the
|
||||
//expression is evaluated by QDeclarativeEngine.
|
||||
if (state() != InferiorStopOk) {
|
||||
QmlInspectorAgent *agent = d->m_inspectorAdapter.agent();
|
||||
quint32 queryId
|
||||
= agent->queryExpressionResult(
|
||||
d->m_inspectorAdapter.currentSelectedDebugId(),
|
||||
expression);
|
||||
if (queryId) {
|
||||
d->queryIds << queryId;
|
||||
} else {
|
||||
executeDebuggerCommand(expression, QmlLanguage);
|
||||
didEvaluate = false;
|
||||
qtMessageLogHandler()->
|
||||
appendItem(
|
||||
new QtMessageLogItem(
|
||||
qtMessageLogHandler()->root(),
|
||||
QtMessageLogHandler::ErrorType,
|
||||
_("Error evaluating expression.")));
|
||||
}
|
||||
} else {
|
||||
didEvaluate = false;
|
||||
executeDebuggerCommand(expression, QmlLanguage);
|
||||
}
|
||||
} else {
|
||||
//Incase of invalid context, show Error message
|
||||
qtMessageLogHandler()->
|
||||
appendItem(new QtMessageLogItem(
|
||||
qtMessageLogHandler()->root(),
|
||||
QtMessageLogHandler::ErrorType,
|
||||
_("Cannot evaluate without "
|
||||
"a valid QML/JS Context.")),
|
||||
qtMessageLogHandler()->rowCount());
|
||||
didEvaluate = false;
|
||||
}
|
||||
}
|
||||
return didEvaluate;
|
||||
|
@@ -49,15 +49,13 @@ class IEditor;
|
||||
}
|
||||
|
||||
namespace Debugger {
|
||||
|
||||
class QmlAdapter;
|
||||
|
||||
namespace Internal {
|
||||
|
||||
class QtMessageLogItem;
|
||||
class QmlAdapter;
|
||||
class QmlEnginePrivate;
|
||||
|
||||
class DEBUGGER_EXPORT QmlEngine : public DebuggerEngine
|
||||
class QmlEngine : public DebuggerEngine
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
611
src/plugins/debugger/qml/qmlinspectoradapter.cpp
Normal file
@@ -0,0 +1,611 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "qmlinspectoradapter.h"
|
||||
|
||||
#include "debuggeractions.h"
|
||||
#include "debuggercore.h"
|
||||
#include "debuggerstringutils.h"
|
||||
#include "qmladapter.h"
|
||||
#include "qmlengine.h"
|
||||
#include "qmlinspectoragent.h"
|
||||
#include "qmllivetextpreview.h"
|
||||
|
||||
#include <coreplugin/actionmanager/actionmanager.h>
|
||||
#include <coreplugin/editormanager/ieditor.h>
|
||||
#include <coreplugin/icore.h>
|
||||
#include <qmldebug/declarativeenginedebugclient.h>
|
||||
#include <qmldebug/declarativetoolsclient.h>
|
||||
#include <qmldebug/qmlenginedebugclient.h>
|
||||
#include <qmldebug/qmltoolsclient.h>
|
||||
#include <qmljseditor/qmljseditorconstants.h>
|
||||
#include <qmljs/qmljsmodelmanagerinterface.h>
|
||||
#include <qmljstools/qmljssemanticinfo.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/savedaction.h>
|
||||
|
||||
using namespace QmlDebug;
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
// Get semantic info from QmlJSTextEditorWidget
|
||||
// (we use the meta object system here to avoid having to link
|
||||
// against qmljseditor)
|
||||
static QmlJSTools::SemanticInfo getSemanticInfo(QPlainTextEdit *qmlJSTextEdit)
|
||||
{
|
||||
QmlJSTools::SemanticInfo info;
|
||||
QTC_ASSERT(QLatin1String(qmlJSTextEdit->metaObject()->className())
|
||||
== QLatin1String("QmlJSEditor::QmlJSTextEditorWidget"),
|
||||
return info);
|
||||
QTC_ASSERT(qmlJSTextEdit->metaObject()->indexOfProperty("semanticInfo")
|
||||
!= -1, return info);
|
||||
|
||||
info = qmlJSTextEdit->property("semanticInfo")
|
||||
.value<QmlJSTools::SemanticInfo>();
|
||||
return info;
|
||||
}
|
||||
|
||||
/*!
|
||||
* QmlInspectorAdapter manages the clients for the inspector, and the
|
||||
* integration with the text editor.
|
||||
*/
|
||||
QmlInspectorAdapter::QmlInspectorAdapter(QmlAdapter *debugAdapter,
|
||||
QmlEngine *engine,
|
||||
QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_debugAdapter(debugAdapter)
|
||||
, m_engine(engine)
|
||||
, m_engineClient(0)
|
||||
, m_toolsClient(0)
|
||||
, m_agent(new QmlInspectorAgent(engine, this))
|
||||
, m_targetToSync(NoTarget)
|
||||
, m_debugIdToSelect(-1)
|
||||
, m_currentSelectedDebugId(-1)
|
||||
, m_listeningToEditorManager(false)
|
||||
, m_selectionCallbackExpected(false)
|
||||
, m_cursorPositionChangedExternally(false)
|
||||
, m_toolsClientConnected(false)
|
||||
, m_inspectorToolsContext("Debugger.QmlInspector")
|
||||
, m_selectAction(new QAction(this))
|
||||
, m_zoomAction(new QAction(this))
|
||||
{
|
||||
connect(m_agent, SIGNAL(objectFetched(QmlDebugObjectReference)),
|
||||
SLOT(onObjectFetched(QmlDebugObjectReference)));
|
||||
connect(m_agent, SIGNAL(objectTreeUpdated()),
|
||||
SLOT(onObjectTreeUpdated()));
|
||||
|
||||
QmlDebugConnection *connection = m_debugAdapter->connection();
|
||||
DeclarativeEngineDebugClient *engineClient1
|
||||
= new DeclarativeEngineDebugClient(connection);
|
||||
connect(engineClient1, SIGNAL(newStatus(QmlDebugClient::Status)),
|
||||
this, SLOT(clientStatusChanged(QmlDebugClient::Status)));
|
||||
connect(engineClient1, SIGNAL(newStatus(QmlDebugClient::Status)),
|
||||
this, SLOT(engineClientStatusChanged(QmlDebugClient::Status)));
|
||||
|
||||
QmlEngineDebugClient *engineClient2 = new QmlEngineDebugClient(connection);
|
||||
connect(engineClient2, SIGNAL(newStatus(QmlDebugClient::Status)),
|
||||
this, SLOT(clientStatusChanged(QmlDebugClient::Status)));
|
||||
connect(engineClient2, SIGNAL(newStatus(QmlDebugClient::Status)),
|
||||
this, SLOT(engineClientStatusChanged(QmlDebugClient::Status)));
|
||||
|
||||
m_engineClients.insert(engineClient1->name(), engineClient1);
|
||||
m_engineClients.insert(engineClient2->name(), engineClient2);
|
||||
|
||||
if (engineClient1->status() == QmlDebugClient::Enabled)
|
||||
setActiveEngineClient(engineClient1);
|
||||
if (engineClient2->status() == QmlDebugClient::Enabled)
|
||||
setActiveEngineClient(engineClient2);
|
||||
|
||||
DeclarativeToolsClient *toolsClient1 = new DeclarativeToolsClient(connection);
|
||||
connect(toolsClient1, SIGNAL(connectedStatusChanged(QmlDebugClient::Status)),
|
||||
this, SLOT(clientStatusChanged(QmlDebugClient::Status)));
|
||||
connect(toolsClient1, SIGNAL(connectedStatusChanged(QmlDebugClient::Status)),
|
||||
this, SLOT(toolsClientStatusChanged(QmlDebugClient::Status)));
|
||||
|
||||
QmlToolsClient *toolsClient2 = new QmlToolsClient(connection);
|
||||
connect(toolsClient2, SIGNAL(connectedStatusChanged(QmlDebugClient::Status)),
|
||||
this, SLOT(clientStatusChanged(QmlDebugClient::Status)));
|
||||
connect(toolsClient2, SIGNAL(connectedStatusChanged(QmlDebugClient::Status)),
|
||||
this, SLOT(toolsClientStatusChanged(QmlDebugClient::Status)));
|
||||
|
||||
// toolbar
|
||||
m_selectAction->setObjectName("QML Select Action");
|
||||
m_zoomAction->setObjectName("QML Zoom Action");
|
||||
m_selectAction->setCheckable(true);
|
||||
m_zoomAction->setCheckable(true);
|
||||
|
||||
connect(m_selectAction, SIGNAL(triggered(bool)),
|
||||
SLOT(onSelectActionTriggered(bool)));
|
||||
connect(m_zoomAction, SIGNAL(triggered(bool)),
|
||||
SLOT(onZoomActionTriggered(bool)));
|
||||
}
|
||||
|
||||
QmlInspectorAdapter::~QmlInspectorAdapter()
|
||||
{
|
||||
}
|
||||
|
||||
BaseEngineDebugClient *QmlInspectorAdapter::engineClient() const
|
||||
{
|
||||
return m_engineClient;
|
||||
}
|
||||
|
||||
BaseToolsClient *QmlInspectorAdapter::toolsClient() const
|
||||
{
|
||||
return m_toolsClient;
|
||||
}
|
||||
|
||||
QmlInspectorAgent *QmlInspectorAdapter::agent() const
|
||||
{
|
||||
return m_agent;
|
||||
}
|
||||
|
||||
int QmlInspectorAdapter::currentSelectedDebugId() const
|
||||
{
|
||||
return m_currentSelectedDebugId;
|
||||
}
|
||||
|
||||
QString QmlInspectorAdapter::currentSelectedDisplayName() const
|
||||
{
|
||||
return m_currentSelectedDebugName;
|
||||
}
|
||||
|
||||
void QmlInspectorAdapter::clientStatusChanged(QmlDebugClient::Status status)
|
||||
{
|
||||
QString serviceName;
|
||||
float version = 0;
|
||||
if (QmlDebugClient *client = qobject_cast<QmlDebugClient*>(sender())) {
|
||||
serviceName = client->name();
|
||||
version = client->serviceVersion();
|
||||
}
|
||||
|
||||
m_debugAdapter->logServiceStatusChange(serviceName, version, status);
|
||||
}
|
||||
|
||||
void QmlInspectorAdapter::toolsClientStatusChanged(QmlDebugClient::Status status)
|
||||
{
|
||||
Core::ICore *core = Core::ICore::instance();
|
||||
Core::ActionManager *am = Core::ICore::actionManager();
|
||||
BaseToolsClient *client = qobject_cast<BaseToolsClient*>(sender());
|
||||
if (status == QmlDebugClient::Enabled) {
|
||||
m_toolsClient = client;
|
||||
|
||||
connect(client, SIGNAL(currentObjectsChanged(QList<int>)),
|
||||
SLOT(selectObjectsFromToolsClient(QList<int>)));
|
||||
connect(client, SIGNAL(logActivity(QString,QString)),
|
||||
m_debugAdapter, SLOT(logServiceActivity(QString,QString)));
|
||||
|
||||
// only enable zoom action for Qt 4.x/old client
|
||||
// (zooming is integrated into selection tool in Qt 5).
|
||||
m_zoomAction->setEnabled(
|
||||
qobject_cast<DeclarativeToolsClient*>(client) != 0);
|
||||
|
||||
// register actions here
|
||||
// because there can be multiple QmlEngines
|
||||
// at the same time (but hopefully one one is connected)
|
||||
am->registerAction(m_selectAction,
|
||||
Core::Id(Constants::QML_SELECTTOOL),
|
||||
m_inspectorToolsContext);
|
||||
am->registerAction(m_zoomAction, Core::Id(Constants::QML_ZOOMTOOL),
|
||||
m_inspectorToolsContext);
|
||||
|
||||
core->updateAdditionalContexts(Core::Context(),
|
||||
m_inspectorToolsContext);
|
||||
|
||||
Utils::SavedAction *action = debuggerCore()->action(QmlUpdateOnSave);
|
||||
connect(action, SIGNAL(valueChanged(QVariant)),
|
||||
SLOT(onUpdateOnSaveChanged(QVariant)));
|
||||
|
||||
action = debuggerCore()->action(ShowAppOnTop);
|
||||
connect(action, SIGNAL(valueChanged(QVariant)),
|
||||
SLOT(onShowAppOnTopChanged(QVariant)));
|
||||
if (action->isChecked())
|
||||
m_toolsClient->showAppOnTop(true);
|
||||
|
||||
m_toolsClientConnected = true;
|
||||
} else if (m_toolsClientConnected
|
||||
&& client == m_toolsClient) {
|
||||
disconnect(client, SIGNAL(currentObjectsChanged(QList<int>)),
|
||||
this, SLOT(selectObjectsFromToolsClient(QList<int>)));
|
||||
disconnect(client, SIGNAL(logActivity(QString,QString)),
|
||||
m_debugAdapter, SLOT(logServiceActivity(QString,QString)));
|
||||
|
||||
am->unregisterAction(m_selectAction,
|
||||
Core::Id(Constants::QML_SELECTTOOL));
|
||||
am->unregisterAction(m_zoomAction,
|
||||
Core::Id(Constants::QML_ZOOMTOOL));
|
||||
|
||||
m_selectAction->setChecked(false);
|
||||
m_zoomAction->setChecked(false);
|
||||
core->updateAdditionalContexts(m_inspectorToolsContext,
|
||||
Core::Context());
|
||||
|
||||
Utils::SavedAction *action = debuggerCore()->action(QmlUpdateOnSave);
|
||||
disconnect(action, 0, this, 0);
|
||||
action = debuggerCore()->action(ShowAppOnTop);
|
||||
disconnect(action, 0, this, 0);
|
||||
|
||||
m_toolsClientConnected = false;
|
||||
}
|
||||
}
|
||||
|
||||
void QmlInspectorAdapter::engineClientStatusChanged(QmlDebugClient::Status status)
|
||||
{
|
||||
if (status != QmlDebugClient::Enabled)
|
||||
return;
|
||||
|
||||
BaseEngineDebugClient *client
|
||||
= qobject_cast<BaseEngineDebugClient*>(sender());
|
||||
QTC_ASSERT(client, return);
|
||||
setActiveEngineClient(client);
|
||||
}
|
||||
|
||||
void QmlInspectorAdapter::selectObjectsFromEditor(const QList<int> &debugIds)
|
||||
{
|
||||
int debugId = debugIds.first();
|
||||
|
||||
if (m_selectionCallbackExpected) {
|
||||
m_selectionCallbackExpected = false;
|
||||
return;
|
||||
}
|
||||
m_cursorPositionChangedExternally = true;
|
||||
|
||||
QmlDebugObjectReference clientRef
|
||||
= agent()->objectForId(debugId);
|
||||
|
||||
// if children haven't been loaded yet do so first, the editor
|
||||
// might actually be interested in the children!
|
||||
if (clientRef.debugId() != debugId
|
||||
|| clientRef.needsMoreData()) {
|
||||
m_targetToSync = ToolTarget;
|
||||
m_debugIdToSelect = debugId;
|
||||
agent()->fetchObject(debugId);
|
||||
} else {
|
||||
selectObject(clientRef, ToolTarget);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlInspectorAdapter::selectObjectsFromToolsClient(const QList<int> &debugIds)
|
||||
{
|
||||
if (debugIds.isEmpty())
|
||||
return;
|
||||
|
||||
int debugId = debugIds.first();
|
||||
|
||||
QmlDebugObjectReference clientRef
|
||||
= agent()->objectForId(debugId);
|
||||
|
||||
if (clientRef.debugId() != debugId) {
|
||||
m_targetToSync = EditorTarget;
|
||||
m_debugIdToSelect = debugId;
|
||||
agent()->fetchObject(debugId);
|
||||
} else {
|
||||
selectObject(clientRef, EditorTarget);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlInspectorAdapter::onObjectFetched(const QmlDebugObjectReference &ref)
|
||||
{
|
||||
if (ref.debugId() == m_debugIdToSelect) {
|
||||
m_debugIdToSelect = -1;
|
||||
selectObject(ref, m_targetToSync);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlInspectorAdapter::onObjectTreeUpdated()
|
||||
{
|
||||
if (m_currentSelectedDebugId == -1) {
|
||||
// select root element on startup
|
||||
if (!m_agent->rootObjects().isEmpty())
|
||||
selectObject(m_agent->rootObjects().first(), NoTarget);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlInspectorAdapter::createPreviewForEditor(Core::IEditor *newEditor)
|
||||
{
|
||||
if (newEditor && newEditor->id()
|
||||
!= QmlJSEditor::Constants::C_QMLJSEDITOR_ID)
|
||||
return;
|
||||
|
||||
QString filename = newEditor->document()->fileName();
|
||||
QmlJS::ModelManagerInterface *modelManager =
|
||||
QmlJS::ModelManagerInterface::instance();
|
||||
QmlJS::Document::Ptr doc = modelManager->snapshot().document(filename);
|
||||
if (!doc) {
|
||||
if (filename.endsWith(".qml")) {
|
||||
// add to list of docs that we have to update when
|
||||
// snapshot figures out that there's a new document
|
||||
m_pendingPreviewDocumentNames.append(filename);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!doc->qmlProgram())
|
||||
return;
|
||||
|
||||
QmlJS::Document::Ptr initdoc = m_loadedSnapshot.document(filename);
|
||||
if (!initdoc)
|
||||
initdoc = doc;
|
||||
|
||||
if (m_textPreviews.contains(filename)) {
|
||||
QmlLiveTextPreview *preview = m_textPreviews.value(filename);
|
||||
preview->associateEditor(newEditor);
|
||||
} else {
|
||||
QmlLiveTextPreview *preview
|
||||
= new QmlLiveTextPreview(doc, initdoc, this, this);
|
||||
connect(preview,
|
||||
SIGNAL(selectedItemsChanged(QList<int>)),
|
||||
SLOT(selectObjectsFromEditor(QList<int>)));
|
||||
preview->setApplyChangesToQmlInspector(
|
||||
debuggerCore()->action(QmlUpdateOnSave)->isChecked());
|
||||
|
||||
m_textPreviews.insert(newEditor->document()->fileName(), preview);
|
||||
preview->associateEditor(newEditor);
|
||||
preview->updateDebugIds();
|
||||
}
|
||||
}
|
||||
|
||||
void QmlInspectorAdapter::removePreviewForEditor(Core::IEditor *editor)
|
||||
{
|
||||
if (QmlLiveTextPreview *preview
|
||||
= m_textPreviews.value(editor->document()->fileName())) {
|
||||
preview->unassociateEditor(editor);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlInspectorAdapter::updatePendingPreviewDocuments(QmlJS::Document::Ptr doc)
|
||||
{
|
||||
int idx = -1;
|
||||
idx = m_pendingPreviewDocumentNames.indexOf(doc->fileName());
|
||||
|
||||
if (idx == -1)
|
||||
return;
|
||||
|
||||
Core::EditorManager *em = Core::EditorManager::instance();
|
||||
QList<Core::IEditor *> editors
|
||||
= em->editorsForFileName(doc->fileName());
|
||||
|
||||
if (editors.isEmpty())
|
||||
return;
|
||||
|
||||
m_pendingPreviewDocumentNames.removeAt(idx);
|
||||
|
||||
Core::IEditor *editor = editors.takeFirst();
|
||||
createPreviewForEditor(editor);
|
||||
QmlLiveTextPreview *preview
|
||||
= m_textPreviews.value(editor->document()->fileName());
|
||||
foreach (Core::IEditor *editor, editors)
|
||||
preview->associateEditor(editor);
|
||||
}
|
||||
|
||||
void QmlInspectorAdapter::onSelectActionTriggered(bool checked)
|
||||
{
|
||||
if (checked) {
|
||||
toolsClient()->setDesignModeBehavior(true);
|
||||
toolsClient()->changeToSelectTool();
|
||||
m_zoomAction->setChecked(false);
|
||||
} else {
|
||||
toolsClient()->setDesignModeBehavior(false);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlInspectorAdapter::onZoomActionTriggered(bool checked)
|
||||
{
|
||||
if (checked) {
|
||||
toolsClient()->setDesignModeBehavior(true);
|
||||
toolsClient()->changeToZoomTool();
|
||||
m_selectAction->setChecked(false);
|
||||
} else {
|
||||
toolsClient()->setDesignModeBehavior(false);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlInspectorAdapter::onShowAppOnTopChanged(const QVariant &value)
|
||||
{
|
||||
bool showAppOnTop = value.toBool();
|
||||
if (m_toolsClient->status() == QmlDebugClient::Enabled)
|
||||
m_toolsClient->showAppOnTop(showAppOnTop);
|
||||
}
|
||||
|
||||
void QmlInspectorAdapter::onUpdateOnSaveChanged(const QVariant &value)
|
||||
{
|
||||
bool updateOnSave = value.toBool();
|
||||
for (QHash<QString, QmlLiveTextPreview *>::const_iterator it
|
||||
= m_textPreviews.constBegin();
|
||||
it != m_textPreviews.constEnd(); ++it) {
|
||||
it.value()->setApplyChangesToQmlInspector(updateOnSave);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlInspectorAdapter::setActiveEngineClient(BaseEngineDebugClient *client)
|
||||
{
|
||||
if (m_engineClient == client)
|
||||
return;
|
||||
|
||||
m_engineClient = client;
|
||||
m_agent->setEngineClient(m_engineClient);
|
||||
|
||||
|
||||
if (m_engineClient &&
|
||||
m_engineClient->status() == QmlDebugClient::Enabled) {
|
||||
QmlJS::ModelManagerInterface *modelManager
|
||||
= QmlJS::ModelManagerInterface::instance();
|
||||
QmlJS::Snapshot snapshot = modelManager->snapshot();
|
||||
for (QHash<QString, QmlLiveTextPreview *>::const_iterator it
|
||||
= m_textPreviews.constBegin();
|
||||
it != m_textPreviews.constEnd(); ++it) {
|
||||
QmlJS::Document::Ptr doc = snapshot.document(it.key());
|
||||
it.value()->resetInitialDoc(doc);
|
||||
}
|
||||
|
||||
initializePreviews();
|
||||
}
|
||||
}
|
||||
|
||||
void QmlInspectorAdapter::initializePreviews()
|
||||
{
|
||||
Core::EditorManager *em = Core::EditorManager::instance();
|
||||
QmlJS::ModelManagerInterface *modelManager
|
||||
= QmlJS::ModelManagerInterface::instance();
|
||||
m_loadedSnapshot = modelManager->snapshot();
|
||||
|
||||
if (!m_listeningToEditorManager) {
|
||||
m_listeningToEditorManager = true;
|
||||
connect(em, SIGNAL(editorAboutToClose(Core::IEditor*)),
|
||||
this, SLOT(removePreviewForEditor(Core::IEditor*)));
|
||||
connect(em, SIGNAL(editorOpened(Core::IEditor*)),
|
||||
this, SLOT(createPreviewForEditor(Core::IEditor*)));
|
||||
connect(modelManager,
|
||||
SIGNAL(documentChangedOnDisk(QmlJS::Document::Ptr)),
|
||||
this, SLOT(updatePendingPreviewDocuments(QmlJS::Document::Ptr)));
|
||||
}
|
||||
|
||||
// initial update
|
||||
foreach (Core::IEditor *editor, em->openedEditors())
|
||||
createPreviewForEditor(editor);
|
||||
}
|
||||
|
||||
void QmlInspectorAdapter::showConnectionStatusMessage(const QString &message)
|
||||
{
|
||||
m_engine->showMessage(_("QML Inspector: ") + message, LogStatus);
|
||||
}
|
||||
|
||||
void QmlInspectorAdapter::gotoObjectReferenceDefinition(
|
||||
const QmlDebugObjectReference &obj)
|
||||
{
|
||||
if (m_cursorPositionChangedExternally) {
|
||||
m_cursorPositionChangedExternally = false;
|
||||
return;
|
||||
}
|
||||
|
||||
QmlDebugFileReference source = obj.source();
|
||||
|
||||
const QString fileName = m_engine->toFileInProject(source.url());
|
||||
|
||||
Core::EditorManager *editorManager = Core::EditorManager::instance();
|
||||
Core::IEditor *currentEditor = editorManager->currentEditor();
|
||||
Core::IEditor *editor = editorManager->openEditor(fileName);
|
||||
TextEditor::ITextEditor *textEditor
|
||||
= qobject_cast<TextEditor::ITextEditor*>(editor);
|
||||
|
||||
if (currentEditor != editor)
|
||||
m_selectionCallbackExpected = true;
|
||||
|
||||
if (textEditor) {
|
||||
QmlDebugObjectReference ref = objectReferenceForLocation(fileName);
|
||||
if (ref.debugId() != obj.debugId()) {
|
||||
m_selectionCallbackExpected = true;
|
||||
editorManager->addCurrentPositionToNavigationHistory();
|
||||
textEditor->gotoLine(source.lineNumber());
|
||||
textEditor->widget()->setFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QmlDebugObjectReference QmlInspectorAdapter::objectReferenceForLocation(
|
||||
const QString &fileName, int cursorPosition) const
|
||||
{
|
||||
Core::EditorManager *editorManager = Core::EditorManager::instance();
|
||||
Core::IEditor *editor = editorManager->openEditor(fileName);
|
||||
TextEditor::ITextEditor *textEditor
|
||||
= qobject_cast<TextEditor::ITextEditor*>(editor);
|
||||
|
||||
if (textEditor
|
||||
&& textEditor->id() == QmlJSEditor::Constants::C_QMLJSEDITOR_ID) {
|
||||
if (cursorPosition == -1)
|
||||
cursorPosition = textEditor->position();
|
||||
TextEditor::BaseTextEditor *baseTextEditor =
|
||||
static_cast<TextEditor::BaseTextEditor*>(editor);
|
||||
QPlainTextEdit *editWidget
|
||||
= qobject_cast<QPlainTextEdit*>(baseTextEditor->widget());
|
||||
|
||||
QmlJSTools::SemanticInfo semanticInfo = getSemanticInfo(editWidget);
|
||||
|
||||
if (QmlJS::AST::Node *node
|
||||
= semanticInfo.declaringMemberNoProperties(cursorPosition)) {
|
||||
if (QmlJS::AST::UiObjectMember *objMember
|
||||
= node->uiObjectMemberCast()) {
|
||||
return agent()->objectForLocation(
|
||||
objMember->firstSourceLocation().startLine,
|
||||
objMember->firstSourceLocation().startColumn);
|
||||
}
|
||||
}
|
||||
}
|
||||
return QmlDebugObjectReference();
|
||||
}
|
||||
|
||||
inline QString displayName(const QmlDebugObjectReference &obj)
|
||||
{
|
||||
// special! state names
|
||||
if (obj.className() == "State") {
|
||||
foreach (const QmlDebugPropertyReference &prop, obj.properties()) {
|
||||
if (prop.name() == "name")
|
||||
return prop.value().toString();
|
||||
}
|
||||
}
|
||||
|
||||
// has id?
|
||||
if (!obj.idString().isEmpty())
|
||||
return obj.idString();
|
||||
|
||||
// return the simplified class name then
|
||||
QString objTypeName = obj.className();
|
||||
QStringList declarativeStrings;
|
||||
declarativeStrings << QLatin1String("QDeclarative")
|
||||
<< QLatin1String("QQml");
|
||||
foreach (const QString &str, declarativeStrings) {
|
||||
if (objTypeName.startsWith(str)) {
|
||||
objTypeName = objTypeName.mid(str.length()).section('_', 0, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return QString("<%1>").arg(objTypeName);
|
||||
}
|
||||
|
||||
void QmlInspectorAdapter::selectObject(const QmlDebugObjectReference &obj,
|
||||
SelectionTarget target)
|
||||
{
|
||||
if (target == ToolTarget)
|
||||
m_toolsClient->setObjectIdList(
|
||||
QList<QmlDebugObjectReference>() << obj);
|
||||
|
||||
if (target == EditorTarget)
|
||||
gotoObjectReferenceDefinition(obj);
|
||||
|
||||
agent()->selectObjectInTree(obj.debugId());
|
||||
|
||||
m_currentSelectedDebugId = obj.debugId();
|
||||
m_currentSelectedDebugName = displayName(obj);
|
||||
emit selectionChanged();
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Debugger
|
150
src/plugins/debugger/qml/qmlinspectoradapter.h
Normal file
@@ -0,0 +1,150 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QMLINSPECTORADAPTER_H
|
||||
#define QMLINSPECTORADAPTER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QStringList>
|
||||
|
||||
#include <coreplugin/icontext.h>
|
||||
#include <qmldebug/qmldebugclient.h>
|
||||
#include <qmljs/qmljsdocument.h>
|
||||
|
||||
namespace Core {
|
||||
class IEditor;
|
||||
}
|
||||
|
||||
namespace QmlDebug {
|
||||
class BaseEngineDebugClient;
|
||||
class BaseToolsClient;
|
||||
class QmlDebugObjectReference;
|
||||
}
|
||||
|
||||
using namespace QmlDebug;
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
class WatchTreeView;
|
||||
class QmlAdapter;
|
||||
class QmlEngine;
|
||||
class QmlInspectorAgent;
|
||||
class QmlLiveTextPreview;
|
||||
|
||||
class QmlInspectorAdapter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QmlInspectorAdapter(QmlAdapter *debugAdapter, QmlEngine *engine,
|
||||
QObject *parent = 0);
|
||||
~QmlInspectorAdapter();
|
||||
|
||||
BaseEngineDebugClient *engineClient() const;
|
||||
BaseToolsClient *toolsClient() const;
|
||||
QmlInspectorAgent *agent() const;
|
||||
|
||||
int currentSelectedDebugId() const;
|
||||
QString currentSelectedDisplayName() const;
|
||||
|
||||
signals:
|
||||
void expressionResult();
|
||||
void selectionChanged();
|
||||
|
||||
private slots:
|
||||
void clientStatusChanged(QmlDebugClient::Status status);
|
||||
void toolsClientStatusChanged(QmlDebugClient::Status status);
|
||||
void engineClientStatusChanged(QmlDebugClient::Status status);
|
||||
|
||||
void selectObjectsFromEditor(const QList<int> &debugIds);
|
||||
void selectObjectsFromToolsClient(const QList<int> &debugIds);
|
||||
void onObjectFetched(const QmlDebugObjectReference &ref);
|
||||
void onObjectTreeUpdated();
|
||||
|
||||
void createPreviewForEditor(Core::IEditor *newEditor);
|
||||
void removePreviewForEditor(Core::IEditor *editor);
|
||||
void updatePendingPreviewDocuments(QmlJS::Document::Ptr doc);
|
||||
|
||||
void onSelectActionTriggered(bool checked);
|
||||
void onZoomActionTriggered(bool checked);
|
||||
void onShowAppOnTopChanged(const QVariant &value);
|
||||
void onUpdateOnSaveChanged(const QVariant &value);
|
||||
|
||||
private:
|
||||
void setActiveEngineClient(BaseEngineDebugClient *client);
|
||||
|
||||
void initializePreviews();
|
||||
void showConnectionStatusMessage(const QString &message);
|
||||
|
||||
void gotoObjectReferenceDefinition(const QmlDebugObjectReference &obj);
|
||||
QmlDebugObjectReference objectReferenceForLocation(
|
||||
const QString &fileName, int cursorPosition = -1) const;
|
||||
|
||||
enum SelectionTarget { NoTarget, ToolTarget, EditorTarget };
|
||||
void selectObject(
|
||||
const QmlDebugObjectReference &objectReference,
|
||||
SelectionTarget target);
|
||||
|
||||
|
||||
QmlAdapter *m_debugAdapter;
|
||||
QmlEngine *m_engine;
|
||||
BaseEngineDebugClient *m_engineClient;
|
||||
QHash<QString, BaseEngineDebugClient*> m_engineClients;
|
||||
BaseToolsClient *m_toolsClient;
|
||||
QmlInspectorAgent *m_agent;
|
||||
|
||||
SelectionTarget m_targetToSync;
|
||||
int m_debugIdToSelect;
|
||||
|
||||
int m_currentSelectedDebugId;
|
||||
QString m_currentSelectedDebugName;
|
||||
|
||||
// Qml/JS editor integration
|
||||
bool m_listeningToEditorManager;
|
||||
QHash<QString, QmlLiveTextPreview *> m_textPreviews;
|
||||
QmlJS::Snapshot m_loadedSnapshot; //the snapshot loaded by the viewer
|
||||
QStringList m_pendingPreviewDocumentNames;
|
||||
bool m_selectionCallbackExpected;
|
||||
bool m_cursorPositionChangedExternally;
|
||||
|
||||
// toolbar
|
||||
bool m_toolsClientConnected;
|
||||
Core::Context m_inspectorToolsContext;
|
||||
QAction *m_selectAction;
|
||||
QAction *m_zoomAction;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Debugger
|
||||
|
||||
#endif // QMLINSPECTORADAPTER_H
|
786
src/plugins/debugger/qml/qmlinspectoragent.cpp
Normal file
@@ -0,0 +1,786 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "qmlinspectoragent.h"
|
||||
|
||||
#include "debuggeractions.h"
|
||||
#include "debuggercore.h"
|
||||
#include "debuggerengine.h"
|
||||
#include "debuggerstringutils.h"
|
||||
#include "watchhandler.h"
|
||||
|
||||
#include <qmldebug/qmldebugconstants.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/savedaction.h>
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
enum {
|
||||
debug = false
|
||||
};
|
||||
|
||||
/*!
|
||||
* DebuggerAgent updates the watchhandler with the object tree data.
|
||||
*/
|
||||
QmlInspectorAgent::QmlInspectorAgent(DebuggerEngine *engine, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_engine(engine)
|
||||
, m_engineClient(0)
|
||||
, m_engineQueryId(0)
|
||||
, m_rootContextQueryId(0)
|
||||
, m_objectToSelect(-1)
|
||||
{
|
||||
connect(debuggerCore()->action(ShowQmlObjectTree),
|
||||
SIGNAL(valueChanged(QVariant)), SLOT(updateStatus()));
|
||||
}
|
||||
|
||||
void QmlInspectorAgent::refreshObjectTree()
|
||||
{
|
||||
if (debug)
|
||||
qDebug() << __FUNCTION__ << "()";
|
||||
|
||||
if (!m_rootContextQueryId) {
|
||||
m_objectTreeQueryIds.clear();
|
||||
queryEngineContext(m_engines.value(0).debugId());
|
||||
}
|
||||
}
|
||||
|
||||
void QmlInspectorAgent::fetchObject(int debugId)
|
||||
{
|
||||
if (debug)
|
||||
qDebug() << __FUNCTION__ << "(" << debugId << ")";
|
||||
|
||||
m_fetchCurrentObjectsQueryIds
|
||||
<< fetchContextObject(QmlDebugObjectReference(debugId));
|
||||
}
|
||||
|
||||
quint32 QmlInspectorAgent::queryExpressionResult(int debugId,
|
||||
const QString &expression)
|
||||
{
|
||||
if (debug)
|
||||
qDebug() << __FUNCTION__ << "(" << debugId << expression
|
||||
<< m_engines.value(0).debugId() << ")";
|
||||
|
||||
return m_engineClient->queryExpressionResult(debugId, expression,
|
||||
m_engines.value(0).debugId());
|
||||
}
|
||||
|
||||
void QmlInspectorAgent::updateWatchData(const WatchData &data)
|
||||
{
|
||||
if (debug)
|
||||
qDebug() << __FUNCTION__ << "(" << data.id << ")";
|
||||
|
||||
if (data.id) {
|
||||
// objects
|
||||
QmlDebugObjectReference ref(data.id);
|
||||
m_fetchCurrentObjectsQueryIds << fetchContextObject(ref);
|
||||
WatchData d = data;
|
||||
d.setAllUnneeded();
|
||||
m_engine->watchHandler()->beginCycle(InspectWatch, false);
|
||||
m_engine->watchHandler()->insertData(d);
|
||||
m_engine->watchHandler()->endCycle(InspectWatch);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlInspectorAgent::selectObjectInTree(int debugId)
|
||||
{
|
||||
if (debug) {
|
||||
qDebug() << __FUNCTION__ << "(" << debugId << ")";
|
||||
qDebug() << " " << debugId << "already fetched? "
|
||||
<< m_debugIdToIname.contains(debugId);
|
||||
}
|
||||
|
||||
if (m_debugIdToIname.contains(debugId)) {
|
||||
QByteArray iname = m_debugIdToIname.value(debugId);
|
||||
QTC_ASSERT(iname.startsWith("inspect."), qDebug() << iname);
|
||||
QModelIndex itemIndex = m_engine->watchHandler()->itemIndex(iname);
|
||||
QTC_ASSERT(itemIndex.isValid(),
|
||||
qDebug() << "No for " << debugId << ", iname " << iname; return;);
|
||||
if (debug)
|
||||
qDebug() << " selecting" << iname << "in tree";
|
||||
m_engine->watchHandler()->setCurrentModelIndex(InspectWatch, itemIndex);
|
||||
m_objectToSelect = 0;
|
||||
} else {
|
||||
// we've to fetch it
|
||||
m_objectToSelect = debugId;
|
||||
m_fetchCurrentObjectsQueryIds
|
||||
<< fetchContextObject(QmlDebugObjectReference(debugId));
|
||||
}
|
||||
}
|
||||
|
||||
quint32 QmlInspectorAgent::setBindingForObject(int objectDebugId,
|
||||
const QString &propertyName,
|
||||
const QVariant &value,
|
||||
bool isLiteralValue,
|
||||
QString source,
|
||||
int line)
|
||||
{
|
||||
if (debug)
|
||||
qDebug() << __FUNCTION__ << "(" << objectDebugId << propertyName
|
||||
<< value.toString() << isLiteralValue << source << line << ")";
|
||||
|
||||
if (objectDebugId == -1)
|
||||
return 0;
|
||||
|
||||
if (propertyName == QLatin1String("id"))
|
||||
return 0; // Crashes the QMLViewer.
|
||||
|
||||
if (!isConnected()
|
||||
|| !debuggerCore()->boolSetting(ShowQmlObjectTree))
|
||||
return 0;
|
||||
|
||||
log(LogSend, QString("SET_BINDING %1 %2 %3 %4").arg(
|
||||
QString::number(objectDebugId), propertyName, value.toString(),
|
||||
QString(isLiteralValue ? "true" : "false")));
|
||||
|
||||
quint32 queryId = m_engineClient->setBindingForObject(
|
||||
objectDebugId, propertyName, value.toString(), isLiteralValue,
|
||||
source, line);
|
||||
|
||||
if (!queryId)
|
||||
log(LogSend, QString("SET_BINDING failed!"));
|
||||
|
||||
return queryId;
|
||||
}
|
||||
|
||||
quint32 QmlInspectorAgent::setMethodBodyForObject(int objectDebugId,
|
||||
const QString &methodName,
|
||||
const QString &methodBody)
|
||||
{
|
||||
if (debug)
|
||||
qDebug() << __FUNCTION__ << "(" << objectDebugId
|
||||
<< methodName << methodBody << ")";
|
||||
|
||||
if (objectDebugId == -1)
|
||||
return 0;
|
||||
|
||||
if (!isConnected()
|
||||
|| !debuggerCore()->boolSetting(ShowQmlObjectTree))
|
||||
return 0;
|
||||
|
||||
log(LogSend, QString("SET_METHOD_BODY %1 %2 %3").arg(
|
||||
QString::number(objectDebugId), methodName, methodBody));
|
||||
|
||||
quint32 queryId = m_engineClient->setMethodBody(
|
||||
objectDebugId, methodName, methodBody);
|
||||
|
||||
if (!queryId)
|
||||
log(LogSend, QString("failed!"));
|
||||
|
||||
return queryId;
|
||||
}
|
||||
|
||||
quint32 QmlInspectorAgent::resetBindingForObject(int objectDebugId,
|
||||
const QString &propertyName)
|
||||
{
|
||||
if (debug)
|
||||
qDebug() << __FUNCTION__ << "(" << objectDebugId
|
||||
<< propertyName << ")";
|
||||
|
||||
if (objectDebugId == -1)
|
||||
return 0;
|
||||
|
||||
if (!isConnected()
|
||||
|| !debuggerCore()->boolSetting(ShowQmlObjectTree))
|
||||
return 0;
|
||||
|
||||
log(LogSend, QString("RESET_BINDING %1 %2").arg(
|
||||
QString::number(objectDebugId), propertyName));
|
||||
|
||||
quint32 queryId = m_engineClient->resetBindingForObject(
|
||||
objectDebugId, propertyName);
|
||||
|
||||
if (!queryId)
|
||||
log(LogSend, QString("failed!"));
|
||||
|
||||
return queryId;
|
||||
}
|
||||
|
||||
|
||||
QList<QmlDebugObjectReference> QmlInspectorAgent::objects() const
|
||||
{
|
||||
QList<QmlDebugObjectReference> result;
|
||||
foreach (const QmlDebugObjectReference &it, m_rootObjects)
|
||||
result.append(objects(it));
|
||||
return result;
|
||||
}
|
||||
|
||||
QmlDebugObjectReference QmlInspectorAgent::objectForId(int debugId) const
|
||||
{
|
||||
foreach (const QmlDebugObjectReference &it, m_rootObjects) {
|
||||
QmlDebugObjectReference result = objectForId(debugId, it);
|
||||
if (result.debugId() == debugId)
|
||||
return result;
|
||||
}
|
||||
return QmlDebugObjectReference();
|
||||
}
|
||||
|
||||
QmlDebugObjectReference QmlInspectorAgent::objectForId(
|
||||
const QString &objectId) const
|
||||
{
|
||||
if (!objectId.isEmpty() && objectId[0].isLower()) {
|
||||
const QList<QmlDebugObjectReference> refs = objects();
|
||||
foreach (const QmlDebugObjectReference &ref, refs) {
|
||||
if (ref.idString() == objectId)
|
||||
return ref;
|
||||
}
|
||||
}
|
||||
return QmlDebugObjectReference();
|
||||
}
|
||||
|
||||
QmlDebugObjectReference QmlInspectorAgent::objectForLocation(
|
||||
int line, int column) const
|
||||
{
|
||||
const QList<QmlDebugObjectReference> refs = objects();
|
||||
foreach (const QmlDebugObjectReference &ref, refs) {
|
||||
if (ref.source().lineNumber() == line
|
||||
&& ref.source().columnNumber() == column)
|
||||
return ref;
|
||||
}
|
||||
|
||||
return QmlDebugObjectReference();
|
||||
}
|
||||
|
||||
bool QmlInspectorAgent::addObjectWatch(int objectDebugId)
|
||||
{
|
||||
if (debug)
|
||||
qDebug() << __FUNCTION__ << "(" << objectDebugId << ")";
|
||||
|
||||
if (objectDebugId == -1)
|
||||
return false;
|
||||
|
||||
if (!isConnected()
|
||||
|| !debuggerCore()->boolSetting(ShowQmlObjectTree))
|
||||
return false;
|
||||
|
||||
// already set
|
||||
if (m_objectWatches.contains(objectDebugId))
|
||||
return true;
|
||||
|
||||
QmlDebugObjectReference ref = objectForId(objectDebugId);
|
||||
if (ref.debugId() != objectDebugId)
|
||||
return false;
|
||||
|
||||
// is flooding the debugging output log!
|
||||
// log(LogSend, QString("WATCH_PROPERTY %1").arg(objectDebugId));
|
||||
|
||||
if (m_engineClient->addWatch(ref))
|
||||
m_objectWatches.append(objectDebugId);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool QmlInspectorAgent::isObjectBeingWatched(int objectDebugId)
|
||||
{
|
||||
return m_objectWatches.contains(objectDebugId);
|
||||
}
|
||||
|
||||
bool QmlInspectorAgent::removeObjectWatch(int objectDebugId)
|
||||
{
|
||||
if (debug)
|
||||
qDebug() << __FUNCTION__ << "(" << objectDebugId << ")";
|
||||
|
||||
if (objectDebugId == -1)
|
||||
return false;
|
||||
|
||||
if (!m_objectWatches.contains(objectDebugId))
|
||||
return false;
|
||||
|
||||
if (!isConnected())
|
||||
return false;
|
||||
|
||||
m_objectWatches.removeOne(objectDebugId);
|
||||
return true;
|
||||
}
|
||||
|
||||
void QmlInspectorAgent::removeAllObjectWatches()
|
||||
{
|
||||
if (debug)
|
||||
qDebug() << __FUNCTION__ << "()";
|
||||
|
||||
foreach (int watchedObject, m_objectWatches)
|
||||
removeObjectWatch(watchedObject);
|
||||
}
|
||||
|
||||
void QmlInspectorAgent::setEngineClient(BaseEngineDebugClient *client)
|
||||
{
|
||||
if (m_engineClient == client)
|
||||
return;
|
||||
|
||||
if (m_engineClient) {
|
||||
disconnect(m_engineClient, SIGNAL(newStatus(QmlDebugClient::Status)),
|
||||
this, SLOT(updateStatus()));
|
||||
disconnect(m_engineClient, SIGNAL(result(quint32,QVariant,QByteArray)),
|
||||
this, SLOT(onResult(quint32,QVariant,QByteArray)));
|
||||
disconnect(m_engineClient, SIGNAL(newObjects()),
|
||||
this, SLOT(newObjects()));
|
||||
}
|
||||
|
||||
m_engineClient = client;
|
||||
|
||||
if (m_engineClient) {
|
||||
connect(m_engineClient, SIGNAL(newStatus(QmlDebugClient::Status)),
|
||||
this, SLOT(updateStatus()));
|
||||
connect(m_engineClient, SIGNAL(result(quint32,QVariant,QByteArray)),
|
||||
this, SLOT(onResult(quint32,QVariant,QByteArray)));
|
||||
connect(m_engineClient, SIGNAL(newObjects()),
|
||||
this, SLOT(newObjects()));
|
||||
}
|
||||
|
||||
updateStatus();
|
||||
}
|
||||
|
||||
void QmlInspectorAgent::updateStatus()
|
||||
{
|
||||
if (m_engineClient
|
||||
&& (m_engineClient->status() == QmlDebugClient::Enabled)
|
||||
&& debuggerCore()->boolSetting(ShowQmlObjectTree)) {
|
||||
reloadEngines();
|
||||
} else {
|
||||
// clear view
|
||||
m_engine->watchHandler()->beginCycle(InspectWatch, true);
|
||||
m_engine->watchHandler()->endCycle(InspectWatch);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlInspectorAgent::onResult(quint32 queryId, const QVariant &value,
|
||||
const QByteArray &type)
|
||||
{
|
||||
if (debug)
|
||||
qDebug() << __FUNCTION__ << "() ...";
|
||||
|
||||
if (type == _("FETCH_OBJECT_R")) {
|
||||
log(LogReceive, _("FETCH_OBJECT_R %1").arg(
|
||||
qvariant_cast<QmlDebugObjectReference>(value).idString()));
|
||||
} else {
|
||||
log(LogReceive, QLatin1String(type));
|
||||
}
|
||||
|
||||
if (m_objectTreeQueryIds.contains(queryId)) {
|
||||
m_objectTreeQueryIds.removeOne(queryId);
|
||||
objectTreeFetched(qvariant_cast<QmlDebugObjectReference>(value));
|
||||
} else if (queryId == m_engineQueryId) {
|
||||
m_engineQueryId = 0;
|
||||
updateEngineList(qvariant_cast<QmlDebugEngineReferenceList>(value));
|
||||
} else if (queryId == m_rootContextQueryId) {
|
||||
m_rootContextQueryId = 0;
|
||||
rootContextChanged(qvariant_cast<QmlDebugContextReference>(value));
|
||||
} else if (m_fetchCurrentObjectsQueryIds.contains(queryId)) {
|
||||
m_fetchCurrentObjectsQueryIds.removeOne(queryId);
|
||||
QmlDebugObjectReference obj
|
||||
= qvariant_cast<QmlDebugObjectReference>(value);
|
||||
m_fetchCurrentObjects.push_front(obj);
|
||||
onCurrentObjectsFetched(obj);
|
||||
} else {
|
||||
emit expressionResult(queryId, value);
|
||||
}
|
||||
|
||||
if (debug)
|
||||
qDebug() << __FUNCTION__ << "done";
|
||||
|
||||
}
|
||||
|
||||
void QmlInspectorAgent::newObjects()
|
||||
{
|
||||
if (debug)
|
||||
qDebug() << __FUNCTION__ << "()";
|
||||
|
||||
log(LogReceive, QString("OBJECT_CREATED"));
|
||||
refreshObjectTree();
|
||||
}
|
||||
|
||||
void QmlInspectorAgent::reloadEngines()
|
||||
{
|
||||
if (debug)
|
||||
qDebug() << __FUNCTION__ << "()";
|
||||
|
||||
if (!isConnected())
|
||||
return;
|
||||
|
||||
log(LogSend, _("LIST_ENGINES"));
|
||||
|
||||
m_engineQueryId = m_engineClient->queryAvailableEngines();
|
||||
}
|
||||
|
||||
void QmlInspectorAgent::queryEngineContext(int id)
|
||||
{
|
||||
if (debug)
|
||||
qDebug() << __FUNCTION__ << "(" << id << ")";
|
||||
|
||||
if (id < 0)
|
||||
return;
|
||||
|
||||
if (!isConnected()
|
||||
|| !debuggerCore()->boolSetting(ShowQmlObjectTree))
|
||||
return;
|
||||
|
||||
log(LogSend, QString("LIST_OBJECTS %1").arg(QString::number(id)));
|
||||
|
||||
m_rootContextQueryId
|
||||
= m_engineClient->queryRootContexts(QmlDebugEngineReference(id));
|
||||
}
|
||||
|
||||
quint32 QmlInspectorAgent::fetchContextObject(const QmlDebugObjectReference &obj)
|
||||
{
|
||||
if (debug)
|
||||
qDebug() << __FUNCTION__ << "(" << obj << ")";
|
||||
|
||||
if (!isConnected()
|
||||
|| !debuggerCore()->boolSetting(ShowQmlObjectTree))
|
||||
return 0;
|
||||
|
||||
log(LogSend, QString("FETCH_OBJECT %1").arg(obj.idString()));
|
||||
quint32 queryId = m_engineClient->queryObject(obj);
|
||||
if (debug)
|
||||
qDebug() << __FUNCTION__ << "(" << obj.debugId() << ")"
|
||||
<< " - query id" << queryId;
|
||||
return queryId;
|
||||
}
|
||||
|
||||
// fetch the root objects from the context + any child contexts
|
||||
void QmlInspectorAgent::fetchRootObjects(const QmlDebugContextReference &context,
|
||||
bool clear)
|
||||
{
|
||||
if (debug)
|
||||
qDebug() << __FUNCTION__ << "(" << context << clear << ")";
|
||||
|
||||
if (!isConnected()
|
||||
|| !debuggerCore()->boolSetting(ShowQmlObjectTree))
|
||||
return;
|
||||
|
||||
if (clear) {
|
||||
m_rootObjects.clear();
|
||||
m_objectTreeQueryIds.clear();
|
||||
}
|
||||
foreach (const QmlDebugObjectReference & obj, context.objects()) {
|
||||
quint32 queryId = 0;
|
||||
using namespace QmlDebug::Constants;
|
||||
if (m_engineClient->objectName() == QML_DEBUGGER &&
|
||||
m_engineClient->serviceVersion() >= CURRENT_SUPPORTED_VERSION) {
|
||||
//Fetch only root objects
|
||||
if (obj.parentId() == -1)
|
||||
queryId = fetchContextObject(obj);
|
||||
} else {
|
||||
queryId = m_engineClient->queryObjectRecursive(obj);
|
||||
}
|
||||
|
||||
if (queryId)
|
||||
m_objectTreeQueryIds << queryId;
|
||||
}
|
||||
foreach (const QmlDebugContextReference &child, context.contexts())
|
||||
fetchRootObjects(child, false);
|
||||
}
|
||||
|
||||
void QmlInspectorAgent::updateEngineList(const QmlDebugEngineReferenceList &engines)
|
||||
{
|
||||
if (debug)
|
||||
qDebug() << __FUNCTION__ << "(" << engines << ")";
|
||||
|
||||
m_engines = engines;
|
||||
|
||||
// only care about first engine atm
|
||||
queryEngineContext(engines.first().debugId());
|
||||
}
|
||||
|
||||
void QmlInspectorAgent::rootContextChanged(const QmlDebugContextReference &context)
|
||||
{
|
||||
if (debug)
|
||||
qDebug() << __FUNCTION__ << "(" << context << ")";
|
||||
|
||||
fetchRootObjects(context, true);
|
||||
}
|
||||
|
||||
void QmlInspectorAgent::objectTreeFetched(const QmlDebugObjectReference &object)
|
||||
{
|
||||
if (debug)
|
||||
qDebug() << __FUNCTION__ << "(" << object << ")";
|
||||
|
||||
m_rootObjects.append(object);
|
||||
|
||||
if (m_objectTreeQueryIds.isEmpty()) {
|
||||
int old_count = m_debugIdHash.count();
|
||||
m_debugIdHash.clear();
|
||||
m_debugIdHash.reserve(old_count + 1);
|
||||
m_debugIdToIname.clear();
|
||||
foreach (const QmlDebugObjectReference &it, m_rootObjects)
|
||||
buildDebugIdHashRecursive(it);
|
||||
|
||||
emit objectTreeUpdated();
|
||||
|
||||
// sync tree with watchhandler
|
||||
QList<WatchData> watchData;
|
||||
foreach (const QmlDebugObjectReference &obj, m_rootObjects)
|
||||
watchData.append(buildWatchData(obj, WatchData()));
|
||||
|
||||
WatchHandler *watchHandler = m_engine->watchHandler();
|
||||
watchHandler->beginCycle(InspectWatch, true);
|
||||
watchHandler->insertBulkData(watchData);
|
||||
watchHandler->endCycle(InspectWatch);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlInspectorAgent::onCurrentObjectsFetched(const QmlDebugObjectReference &obj)
|
||||
{
|
||||
if (debug)
|
||||
qDebug() << __FUNCTION__ << "( " << obj << ")";
|
||||
|
||||
// get parents if not known yet
|
||||
if (!getObjectHierarchy(obj))
|
||||
return;
|
||||
|
||||
if (debug)
|
||||
qDebug() << " adding" << m_fetchCurrentObjects << "to tree";
|
||||
|
||||
foreach (const QmlDebugObjectReference &o, m_fetchCurrentObjects)
|
||||
addObjectToTree(o, false);
|
||||
|
||||
QmlDebugObjectReference last = m_fetchCurrentObjects.last();
|
||||
m_fetchCurrentObjects.clear();
|
||||
|
||||
if (m_objectToSelect == last.debugId()) {
|
||||
// select item in view
|
||||
QByteArray iname = m_debugIdToIname.value(last.debugId());
|
||||
QModelIndex itemIndex = m_engine->watchHandler()->itemIndex(iname);
|
||||
QTC_ASSERT(itemIndex.isValid(), return);
|
||||
if (debug)
|
||||
qDebug() << " selecting" << iname << "in tree";
|
||||
m_engine->watchHandler()->setCurrentModelIndex(InspectWatch, itemIndex);
|
||||
m_objectToSelect = -1;
|
||||
}
|
||||
|
||||
emit objectFetched(last);
|
||||
emit objectTreeUpdated();
|
||||
}
|
||||
|
||||
// Fetches all anchestors of object. Returns if all has been fetched already.
|
||||
bool QmlInspectorAgent::getObjectHierarchy(const QmlDebugObjectReference &obj)
|
||||
{
|
||||
if (debug)
|
||||
qDebug() << __FUNCTION__ << "(" << obj << ")";
|
||||
|
||||
QmlDebugObjectReference parent = objectForId(obj.parentId());
|
||||
//for root object
|
||||
if (obj.parentId() == -1)
|
||||
return true;
|
||||
|
||||
//for other objects
|
||||
if (parent.debugId() == -1 || parent.needsMoreData()) {
|
||||
m_fetchCurrentObjectsQueryIds
|
||||
<< fetchContextObject(QmlDebugObjectReference(obj.parentId()));
|
||||
} else {
|
||||
return getObjectHierarchy(parent);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void QmlInspectorAgent::buildDebugIdHashRecursive(const QmlDebugObjectReference &ref)
|
||||
{
|
||||
if (debug)
|
||||
qDebug() << __FUNCTION__ << "(" << ref << ")";
|
||||
|
||||
QUrl fileUrl = ref.source().url();
|
||||
int lineNum = ref.source().lineNumber();
|
||||
int colNum = ref.source().columnNumber();
|
||||
int rev = 0;
|
||||
|
||||
// handle the case where the url contains the revision number encoded.
|
||||
//(for object created by the debugger)
|
||||
static QRegExp rx("(.*)_(\\d+):(\\d+)$");
|
||||
if (rx.exactMatch(fileUrl.path())) {
|
||||
fileUrl.setPath(rx.cap(1));
|
||||
rev = rx.cap(2).toInt();
|
||||
lineNum += rx.cap(3).toInt() - 1;
|
||||
}
|
||||
|
||||
const QString filePath
|
||||
= m_engine->toFileInProject(fileUrl);
|
||||
|
||||
// append the debug ids in the hash
|
||||
QPair<QString, int> file = qMakePair<QString, int>(filePath, rev);
|
||||
QPair<int, int> location = qMakePair<int, int>(lineNum, colNum);
|
||||
if (!m_debugIdHash[file][location].contains(ref.debugId()))
|
||||
m_debugIdHash[file][location].append(ref.debugId());
|
||||
|
||||
foreach (const QmlDebugObjectReference &it, ref.children())
|
||||
buildDebugIdHashRecursive(it);
|
||||
}
|
||||
|
||||
static QByteArray buildIName(const WatchData &parent, int debugId)
|
||||
{
|
||||
if (!parent.isValid())
|
||||
return "inspect." + QByteArray::number(debugId);
|
||||
return parent.iname + "." + QByteArray::number(debugId);
|
||||
}
|
||||
|
||||
static QByteArray buildIName(const WatchData &parent, const QString &name)
|
||||
{
|
||||
return parent.iname + "." + name.toLatin1();
|
||||
}
|
||||
|
||||
QList<WatchData> QmlInspectorAgent::buildWatchData(const QmlDebugObjectReference &obj,
|
||||
const WatchData &parent)
|
||||
{
|
||||
if (debug)
|
||||
qDebug() << __FUNCTION__ << "(" << obj << parent.iname << ")";
|
||||
|
||||
QList<WatchData> list;
|
||||
|
||||
WatchData objWatch;
|
||||
QString name = obj.idString();
|
||||
if (name.isEmpty())
|
||||
name = obj.className();
|
||||
|
||||
// object
|
||||
objWatch.id = obj.debugId();
|
||||
objWatch.exp = name.toLatin1();
|
||||
objWatch.name = name;
|
||||
objWatch.iname = buildIName(parent, obj.debugId());
|
||||
objWatch.type = obj.className().toLatin1();
|
||||
objWatch.value = _("object");
|
||||
objWatch.setHasChildren(true);
|
||||
objWatch.setAllUnneeded();
|
||||
|
||||
list.append(objWatch);
|
||||
m_debugIdToIname.insert(objWatch.id, objWatch.iname);
|
||||
|
||||
// properties
|
||||
WatchData propertiesWatch;
|
||||
propertiesWatch.id = objWatch.id;
|
||||
propertiesWatch.exp = "";
|
||||
propertiesWatch.name = tr("properties");
|
||||
propertiesWatch.iname = objWatch.iname + ".[properties]";
|
||||
propertiesWatch.type = "";
|
||||
propertiesWatch.value = _("list");
|
||||
propertiesWatch.setHasChildren(true);
|
||||
propertiesWatch.setAllUnneeded();
|
||||
|
||||
list.append(propertiesWatch);
|
||||
|
||||
foreach (const QmlDebugPropertyReference &property, obj.properties()) {
|
||||
WatchData propertyWatch;
|
||||
propertyWatch.exp = property.name().toLatin1();
|
||||
propertyWatch.name = property.name();
|
||||
propertyWatch.iname = buildIName(propertiesWatch, property.name());
|
||||
propertyWatch.type = property.valueTypeName().toLatin1();
|
||||
propertyWatch.value = property.value().toString();
|
||||
propertyWatch.setAllUnneeded();
|
||||
propertyWatch.setHasChildren(false);
|
||||
list.append(propertyWatch);
|
||||
}
|
||||
|
||||
// recurse
|
||||
foreach (const QmlDebugObjectReference &child, obj.children())
|
||||
list.append(buildWatchData(child, objWatch));
|
||||
return list;
|
||||
}
|
||||
|
||||
void QmlInspectorAgent::addObjectToTree(const QmlDebugObjectReference &obj,
|
||||
bool notify)
|
||||
{
|
||||
int count = m_rootObjects.count();
|
||||
for (int i = 0; i < count; i++) {
|
||||
int parentId = obj.parentId();
|
||||
if (m_engineClient->serviceVersion() < 2) {
|
||||
// we don't get parentId in qt 4.x
|
||||
parentId = m_rootObjects[i].insertObjectInTree(obj);
|
||||
}
|
||||
|
||||
if (parentId >= 0) {
|
||||
buildDebugIdHashRecursive(obj);
|
||||
if (notify)
|
||||
emit objectTreeUpdated();
|
||||
|
||||
// find parent
|
||||
QTC_ASSERT(m_debugIdToIname.contains(parentId), break);
|
||||
QByteArray iname = m_debugIdToIname.value(parentId);
|
||||
const WatchData *parent = m_engine->watchHandler()->findItem(iname);
|
||||
if (parent) {
|
||||
QList<WatchData> watches = buildWatchData(obj, *parent);
|
||||
m_engine->watchHandler()->beginCycle(false);
|
||||
m_engine->watchHandler()->insertBulkData(watches);
|
||||
m_engine->watchHandler()->endCycle();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QmlDebugObjectReference QmlInspectorAgent::objectForId(int debugId,
|
||||
const QmlDebugObjectReference &objectRef) const
|
||||
{
|
||||
if (objectRef.debugId() == debugId)
|
||||
return objectRef;
|
||||
|
||||
foreach (const QmlDebugObjectReference &child, objectRef.children()) {
|
||||
QmlDebugObjectReference result = objectForId(debugId, child);
|
||||
if (result.debugId() == debugId)
|
||||
return result;
|
||||
}
|
||||
|
||||
return QmlDebugObjectReference();
|
||||
}
|
||||
|
||||
QList<QmlDebugObjectReference> QmlInspectorAgent::objects(
|
||||
const QmlDebugObjectReference &objectRef) const
|
||||
{
|
||||
QList<QmlDebugObjectReference> result;
|
||||
result.append(objectRef);
|
||||
|
||||
foreach (const QmlDebugObjectReference &child, objectRef.children())
|
||||
result.append(objects(child));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void QmlInspectorAgent::log(QmlInspectorAgent::LogDirection direction,
|
||||
const QString &message)
|
||||
{
|
||||
QString msg = _("Inspector");
|
||||
if (direction == LogSend)
|
||||
msg += _(" sending ");
|
||||
else
|
||||
msg += _(" receiving ");
|
||||
msg += message;
|
||||
|
||||
if (m_engine)
|
||||
m_engine->showMessage(msg, LogDebug);
|
||||
}
|
||||
|
||||
bool QmlInspectorAgent::isConnected()
|
||||
{
|
||||
return m_engineClient
|
||||
&& (m_engineClient->status() == QmlDebugClient::Enabled);
|
||||
}
|
||||
|
||||
} // Internal
|
||||
} // Debugger
|
160
src/plugins/debugger/qml/qmlinspectoragent.h
Normal file
@@ -0,0 +1,160 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QMLINSPECTORAGENT_H
|
||||
#define QMLINSPECTORAGENT_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <qmldebug/baseenginedebugclient.h>
|
||||
#include <watchdata.h>
|
||||
|
||||
using namespace QmlDebug;
|
||||
|
||||
namespace Debugger {
|
||||
|
||||
class DebuggerEngine;
|
||||
|
||||
namespace Internal {
|
||||
|
||||
class WatchData;
|
||||
|
||||
//map <filename, editorRevision> -> <lineNumber, columnNumber> -> debugId
|
||||
typedef
|
||||
QHash<QPair<QString, int>, QHash<QPair<int, int>, QList<int> > > DebugIdHash;
|
||||
|
||||
class QmlInspectorAgent : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QmlInspectorAgent(DebuggerEngine *engine, QObject *parent = 0);
|
||||
|
||||
|
||||
void refreshObjectTree();
|
||||
void fetchObject(int debugId);
|
||||
quint32 queryExpressionResult(int debugId, const QString &expression);
|
||||
|
||||
void updateWatchData(const WatchData &data);
|
||||
void selectObjectInTree(int debugId);
|
||||
|
||||
quint32 setBindingForObject(int objectDebugId,
|
||||
const QString &propertyName,
|
||||
const QVariant &value,
|
||||
bool isLiteralValue,
|
||||
QString source,
|
||||
int line);
|
||||
quint32 setMethodBodyForObject(int objectDebugId, const QString &methodName,
|
||||
const QString &methodBody);
|
||||
quint32 resetBindingForObject(int objectDebugId,
|
||||
const QString &propertyName);
|
||||
|
||||
QList<QmlDebugObjectReference> objects() const;
|
||||
QmlDebugObjectReference objectForId(int debugId) const;
|
||||
QmlDebugObjectReference objectForId(const QString &objectId) const;
|
||||
QmlDebugObjectReference objectForLocation(int line, int column) const;
|
||||
QList<QmlDebugObjectReference> rootObjects() const { return m_rootObjects; }
|
||||
DebugIdHash debugIdHash() const { return m_debugIdHash; }
|
||||
|
||||
bool addObjectWatch(int objectDebugId);
|
||||
bool isObjectBeingWatched(int objectDebugId);
|
||||
bool removeObjectWatch(int objectDebugId);
|
||||
void removeAllObjectWatches();
|
||||
|
||||
void setEngineClient(BaseEngineDebugClient *client);
|
||||
|
||||
signals:
|
||||
void objectTreeUpdated();
|
||||
void objectFetched(const QmlDebugObjectReference &ref);
|
||||
void expressionResult(quint32 queryId, const QVariant &value);
|
||||
void propertyChanged(int debugId, const QByteArray &propertyName,
|
||||
const QVariant &propertyValue);
|
||||
|
||||
private slots:
|
||||
void updateStatus();
|
||||
void onResult(quint32 queryId, const QVariant &value, const QByteArray &type);
|
||||
void newObjects();
|
||||
|
||||
private:
|
||||
void reloadEngines();
|
||||
void queryEngineContext(int id);
|
||||
quint32 fetchContextObject(const QmlDebugObjectReference &obj);
|
||||
void fetchRootObjects(const QmlDebugContextReference &context, bool clear);
|
||||
|
||||
void updateEngineList(const QmlDebugEngineReferenceList &engines);
|
||||
void rootContextChanged(const QmlDebugContextReference &context);
|
||||
void objectTreeFetched(const QmlDebugObjectReference &result);
|
||||
void onCurrentObjectsFetched(const QmlDebugObjectReference &result);
|
||||
bool getObjectHierarchy(const QmlDebugObjectReference &object);
|
||||
|
||||
|
||||
void buildDebugIdHashRecursive(const QmlDebugObjectReference &ref);
|
||||
QList<WatchData> buildWatchData(const QmlDebugObjectReference &obj,
|
||||
const WatchData &parent);
|
||||
void addObjectToTree(const QmlDebugObjectReference &obj, bool notify);
|
||||
|
||||
QmlDebugObjectReference objectForId(
|
||||
int debugId,
|
||||
const QmlDebugObjectReference &ref) const;
|
||||
QList<QmlDebugObjectReference> objects(
|
||||
const QmlDebugObjectReference &objectRef) const;
|
||||
|
||||
|
||||
enum LogDirection {
|
||||
LogSend,
|
||||
LogReceive
|
||||
};
|
||||
void log(LogDirection direction, const QString &message);
|
||||
|
||||
bool isConnected();
|
||||
|
||||
private:
|
||||
DebuggerEngine *m_engine;
|
||||
QmlDebug::BaseEngineDebugClient *m_engineClient;
|
||||
|
||||
quint32 m_engineQueryId;
|
||||
quint32 m_rootContextQueryId;
|
||||
int m_objectToSelect;
|
||||
QList<quint32> m_objectTreeQueryIds;
|
||||
QList<QmlDebugObjectReference> m_rootObjects;
|
||||
QList<quint32> m_fetchCurrentObjectsQueryIds;
|
||||
QList<QmlDebugObjectReference> m_fetchCurrentObjects;
|
||||
QmlDebugEngineReferenceList m_engines;
|
||||
QHash<int, QByteArray> m_debugIdToIname;
|
||||
DebugIdHash m_debugIdHash;
|
||||
|
||||
QList<int> m_objectWatches;
|
||||
};
|
||||
|
||||
} // Internal
|
||||
} // Debugger
|
||||
|
||||
#endif // QMLINSPECTORAGENT_H
|
@@ -30,36 +30,23 @@
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include <typeinfo>
|
||||
#include "qmllivetextpreview.h"
|
||||
|
||||
#include "qmljsinspector.h"
|
||||
#include "qmljsclientproxy.h"
|
||||
#include "qmljslivetextpreview.h"
|
||||
#include "qmlinspectoradapter.h"
|
||||
#include "qmlinspectoragent.h"
|
||||
|
||||
#include "qmljsinspectorconstants.h"
|
||||
#include <qmljseditor/qmljseditorconstants.h>
|
||||
#include <qmljs/qmljsdelta.h>
|
||||
#include <qmljs/parser/qmljsast_p.h>
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
#include <projectexplorer/projectexplorer.h>
|
||||
#include <projectexplorer/project.h>
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/infobar.h>
|
||||
#include <coreplugin/editormanager/ieditor.h>
|
||||
#include <coreplugin/id.h>
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
|
||||
#include <debugger/debuggerconstants.h>
|
||||
|
||||
#include <qmldebug/basetoolsclient.h>
|
||||
#include <qmljseditor/qmljseditorconstants.h>
|
||||
#include <qmljs/parser/qmljsast_p.h>
|
||||
#include <qmljs/qmljsdelta.h>
|
||||
#include <qmljs/qmljsmodelmanagerinterface.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
using namespace QmlJS;
|
||||
using namespace QmlJS::AST;
|
||||
|
||||
namespace QmlJSInspector {
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
/*!
|
||||
@@ -70,10 +57,10 @@ class MapObjectWithDebugReference : public Visitor
|
||||
public:
|
||||
typedef QList<int> DebugIdList;
|
||||
MapObjectWithDebugReference() : activated(0) {}
|
||||
virtual void endVisit(UiObjectDefinition *ast) ;
|
||||
virtual void endVisit(UiObjectBinding *ast) ;
|
||||
virtual bool visit(UiObjectDefinition *ast) ;
|
||||
virtual bool visit(UiObjectBinding *ast) ;
|
||||
virtual void endVisit(UiObjectDefinition *ast);
|
||||
virtual void endVisit(UiObjectBinding *ast);
|
||||
virtual bool visit(UiObjectDefinition *ast);
|
||||
virtual bool visit(UiObjectBinding *ast);
|
||||
|
||||
QHash<QPair<int, int>, DebugIdList> ids;
|
||||
QString filename;
|
||||
@@ -87,298 +74,6 @@ private:
|
||||
int activated;
|
||||
};
|
||||
|
||||
bool MapObjectWithDebugReference::visit(UiObjectDefinition *ast)
|
||||
{
|
||||
if (lookupObjects.contains(ast))
|
||||
activated++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MapObjectWithDebugReference::visit(UiObjectBinding *ast)
|
||||
{
|
||||
if (lookupObjects.contains(ast))
|
||||
activated++;
|
||||
return true;
|
||||
}
|
||||
|
||||
void MapObjectWithDebugReference::endVisit(UiObjectDefinition *ast)
|
||||
{
|
||||
process(ast);
|
||||
if (lookupObjects.contains(ast))
|
||||
activated--;
|
||||
}
|
||||
|
||||
void MapObjectWithDebugReference::endVisit(UiObjectBinding *ast)
|
||||
{
|
||||
process(ast);
|
||||
if (lookupObjects.contains(ast))
|
||||
activated--;
|
||||
}
|
||||
|
||||
void MapObjectWithDebugReference::process(UiObjectMember *ast)
|
||||
{
|
||||
if (lookupObjects.isEmpty() || activated) {
|
||||
SourceLocation loc = ast->firstSourceLocation();
|
||||
QHash<QPair<int, int>, DebugIdList>::const_iterator it
|
||||
= ids.constFind(qMakePair<int, int>(loc.startLine, loc.startColumn));
|
||||
if (it != ids.constEnd())
|
||||
result[ast].append(*it);
|
||||
}
|
||||
}
|
||||
|
||||
void MapObjectWithDebugReference::process(UiObjectBinding *ast)
|
||||
{
|
||||
if (lookupObjects.isEmpty() || activated) {
|
||||
SourceLocation loc = ast->qualifiedTypeNameId->identifierToken;
|
||||
QHash<QPair<int, int>, DebugIdList>::const_iterator it
|
||||
= ids.constFind(qMakePair<int, int>(loc.startLine, loc.startColumn));
|
||||
if (it != ids.constEnd())
|
||||
result[ast].append(*it);
|
||||
}
|
||||
}
|
||||
|
||||
void QmlJSLiveTextPreview::associateEditor(Core::IEditor *editor)
|
||||
{
|
||||
using namespace TextEditor;
|
||||
if (editor->id() == QmlJSEditor::Constants::C_QMLJSEDITOR_ID) {
|
||||
QTC_ASSERT(QLatin1String(editor->widget()->metaObject()->className()) ==
|
||||
QLatin1String("QmlJSEditor::QmlJSTextEditorWidget"),
|
||||
return);
|
||||
|
||||
BaseTextEditorWidget *editWidget
|
||||
= qobject_cast<BaseTextEditorWidget*>(editor->widget());
|
||||
QTC_ASSERT(editWidget, return);
|
||||
|
||||
if (!m_editors.contains(editWidget)) {
|
||||
m_editors << editWidget;
|
||||
if (m_clientProxy.data())
|
||||
connect(editWidget,
|
||||
SIGNAL(selectedElementsChanged(QList<int>,QString)),
|
||||
SLOT(changeSelectedElements(QList<int>,QString)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QmlJSLiveTextPreview::unassociateEditor(Core::IEditor *oldEditor)
|
||||
{
|
||||
using namespace TextEditor;
|
||||
if (oldEditor && oldEditor->id()
|
||||
== QmlJSEditor::Constants::C_QMLJSEDITOR_ID) {
|
||||
BaseTextEditorWidget *editWidget
|
||||
= qobject_cast<BaseTextEditorWidget*>(oldEditor->widget());
|
||||
QTC_ASSERT(editWidget, return);
|
||||
|
||||
if (m_editors.contains(editWidget)) {
|
||||
m_editors.removeOne(editWidget);
|
||||
disconnect(editWidget, 0, this, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QmlJSLiveTextPreview::QmlJSLiveTextPreview(const QmlJS::Document::Ptr &doc,
|
||||
const QmlJS::Document::Ptr &initDoc,
|
||||
ClientProxy *clientProxy,
|
||||
QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_previousDoc(doc)
|
||||
, m_initialDoc(initDoc)
|
||||
, m_applyChangesToQmlInspector(true)
|
||||
, m_clientProxy(clientProxy)
|
||||
, m_nodeForOffset(0)
|
||||
, m_updateNodeForOffset(false)
|
||||
{
|
||||
Q_ASSERT(doc->fileName() == initDoc->fileName());
|
||||
m_filename = doc->fileName();
|
||||
|
||||
connect(QmlJS::ModelManagerInterface::instance(), SIGNAL(documentChangedOnDisk(QmlJS::Document::Ptr)),
|
||||
SLOT(documentChanged(QmlJS::Document::Ptr)));
|
||||
|
||||
if (m_clientProxy.data()) {
|
||||
connect(m_clientProxy.data(), SIGNAL(objectTreeUpdated()),
|
||||
SLOT(updateDebugIds()));
|
||||
}
|
||||
}
|
||||
|
||||
void QmlJSLiveTextPreview::resetInitialDoc(const QmlJS::Document::Ptr &doc)
|
||||
{
|
||||
m_initialDoc = doc;
|
||||
m_previousDoc = doc;
|
||||
m_createdObjects.clear();
|
||||
m_debugIds.clear();
|
||||
m_docWithUnappliedChanges.clear();
|
||||
}
|
||||
|
||||
|
||||
QList<int> QmlJSLiveTextPreview::objectReferencesForOffset(quint32 offset)
|
||||
{
|
||||
QList<int> result;
|
||||
QHashIterator<QmlJS::AST::UiObjectMember*, QList<int> > iter(m_debugIds);
|
||||
QmlJS::AST::UiObjectMember *possibleNode = 0;
|
||||
while(iter.hasNext()) {
|
||||
iter.next();
|
||||
QmlJS::AST::UiObjectMember *member = iter.key();
|
||||
quint32 startOffset = member->firstSourceLocation().offset;
|
||||
quint32 endOffset = member->lastSourceLocation().offset;
|
||||
if (startOffset <= offset && offset <= endOffset) {
|
||||
if (!possibleNode)
|
||||
possibleNode = member;
|
||||
if (possibleNode->firstSourceLocation().offset <= startOffset &&
|
||||
endOffset <= possibleNode->lastSourceLocation().offset)
|
||||
possibleNode = member;
|
||||
}
|
||||
}
|
||||
if (possibleNode) {
|
||||
if (possibleNode != m_nodeForOffset) {
|
||||
//We have found a better match, set flag so that we can
|
||||
//query again to check if this is the best match for the offset
|
||||
m_updateNodeForOffset = true;
|
||||
m_nodeForOffset = possibleNode;
|
||||
}
|
||||
result = m_debugIds.value(possibleNode);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void QmlJSLiveTextPreview::changeSelectedElements(QList<int> offsets,
|
||||
const QString &wordAtCursor)
|
||||
{
|
||||
if (m_editors.isEmpty() || !m_previousDoc || !m_clientProxy)
|
||||
return;
|
||||
|
||||
m_updateNodeForOffset = false;
|
||||
m_lastOffsets = offsets;
|
||||
QmlDebugObjectReference objectRefUnderCursor;
|
||||
objectRefUnderCursor
|
||||
= m_clientProxy.data()->objectReferenceForId(wordAtCursor);
|
||||
|
||||
QList<int> selectedReferences;
|
||||
bool containsReferenceUnderCursor = false;
|
||||
|
||||
foreach(int offset, offsets) {
|
||||
if (offset >= 0) {
|
||||
QList<int> list = objectReferencesForOffset(offset);
|
||||
|
||||
if (!containsReferenceUnderCursor
|
||||
&& objectRefUnderCursor.debugId() != -1) {
|
||||
foreach(int id, list) {
|
||||
if (id == objectRefUnderCursor.debugId()) {
|
||||
containsReferenceUnderCursor = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
selectedReferences << list;
|
||||
}
|
||||
}
|
||||
|
||||
// fallback: use ref under cursor if nothing else is found
|
||||
if (selectedReferences.isEmpty()
|
||||
&& !containsReferenceUnderCursor
|
||||
&& objectRefUnderCursor.debugId() != -1)
|
||||
{
|
||||
selectedReferences << objectRefUnderCursor.debugId();
|
||||
}
|
||||
|
||||
if (!selectedReferences.isEmpty()) {
|
||||
QList<QmlDebugObjectReference> refs;
|
||||
foreach(int i, selectedReferences)
|
||||
refs << QmlDebugObjectReference(i);
|
||||
emit selectedItemsChanged(refs);
|
||||
}
|
||||
}
|
||||
|
||||
static QList<int> findRootObjectRecursive(const QmlDebugObjectReference &object,
|
||||
const Document::Ptr &doc)
|
||||
{
|
||||
QList<int> result;
|
||||
if (object.className() == doc->componentName())
|
||||
result += object.debugId();
|
||||
|
||||
foreach (const QmlDebugObjectReference &it, object.children()) {
|
||||
result += findRootObjectRecursive(it, doc);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void QmlJSLiveTextPreview::updateDebugIds()
|
||||
{
|
||||
if (!m_initialDoc->qmlProgram())
|
||||
return;
|
||||
|
||||
ClientProxy *clientProxy = m_clientProxy.data();
|
||||
if (!clientProxy)
|
||||
return;
|
||||
|
||||
DebugIdHash::const_iterator it
|
||||
= clientProxy->debugIdHash().constFind(
|
||||
qMakePair<QString, int>(m_initialDoc->fileName(), 0));
|
||||
if (it != clientProxy->debugIdHash().constEnd()) {
|
||||
// Map all the object that comes from the document as it has been loaded
|
||||
// by the server.
|
||||
const QmlJS::Document::Ptr &doc = m_initialDoc;
|
||||
|
||||
MapObjectWithDebugReference visitor;
|
||||
visitor.ids = (*it);
|
||||
visitor.filename = doc->fileName();
|
||||
doc->qmlProgram()->accept(&visitor);
|
||||
|
||||
m_debugIds = visitor.result;
|
||||
if (doc != m_previousDoc) {
|
||||
Delta delta;
|
||||
m_debugIds = delta(doc, m_previousDoc, m_debugIds);
|
||||
}
|
||||
}
|
||||
|
||||
const QmlJS::Document::Ptr &doc = m_previousDoc;
|
||||
if (!doc->qmlProgram())
|
||||
return;
|
||||
|
||||
// Map the root nodes of the document.
|
||||
if(doc->qmlProgram()->members && doc->qmlProgram()->members->member) {
|
||||
UiObjectMember *root = doc->qmlProgram()->members->member;
|
||||
QList<int> r;
|
||||
foreach (const QmlDebugObjectReference& it,
|
||||
clientProxy->rootObjectReference()) {
|
||||
r += findRootObjectRecursive(it, doc);
|
||||
}
|
||||
if (!r.isEmpty())
|
||||
m_debugIds[root] += r;
|
||||
}
|
||||
|
||||
// Map the node of the later created objects.
|
||||
for (QHash<Document::Ptr,QSet<UiObjectMember*> >::const_iterator it
|
||||
= m_createdObjects.constBegin();
|
||||
it != m_createdObjects.constEnd(); ++it) {
|
||||
|
||||
const QmlJS::Document::Ptr &doc = it.key();
|
||||
|
||||
DebugIdHash::const_iterator id_it = clientProxy->debugIdHash().constFind(
|
||||
qMakePair<QString, int>(doc->fileName(), doc->editorRevision()));
|
||||
if (id_it == clientProxy->debugIdHash().constEnd())
|
||||
continue;
|
||||
|
||||
MapObjectWithDebugReference visitor;
|
||||
visitor.ids = *id_it;
|
||||
visitor.filename = doc->fileName();
|
||||
visitor.lookupObjects = it.value();
|
||||
doc->qmlProgram()->accept(&visitor);
|
||||
|
||||
Delta::DebugIdMap debugIds = visitor.result;
|
||||
if (doc != m_previousDoc) {
|
||||
Delta delta;
|
||||
debugIds = delta(doc, m_previousDoc, debugIds);
|
||||
}
|
||||
for(Delta::DebugIdMap::const_iterator it2 = debugIds.constBegin();
|
||||
it2 != debugIds.constEnd(); ++it2) {
|
||||
m_debugIds[it2.key()] += it2.value();
|
||||
}
|
||||
}
|
||||
if (m_updateNodeForOffset)
|
||||
changeSelectedElements(m_lastOffsets, QString());
|
||||
}
|
||||
|
||||
|
||||
class UpdateInspector : public Delta {
|
||||
private:
|
||||
static inline QString stripQuotes(const QString &str)
|
||||
@@ -460,7 +155,7 @@ private:
|
||||
ExpressionStatement *expStatement
|
||||
= cast<ExpressionStatement*>(scriptBinding->statement);
|
||||
|
||||
switch(expStatement->expression->kind) {
|
||||
switch (expStatement->expression->kind) {
|
||||
case Node::Kind_NumericLiteral:
|
||||
case Node::Kind_UnaryPlusExpression:
|
||||
case Node::Kind_UnaryMinusExpression:
|
||||
@@ -491,7 +186,8 @@ protected:
|
||||
Q_UNUSED(scriptBinding);
|
||||
Q_UNUSED(parentDefinition);
|
||||
appliedChangesToViewer = true;
|
||||
m_clientProxy->setMethodBodyForObject(debugId, methodName, methodBody);
|
||||
m_inspectorAdapter->engineClient()->setMethodBody(debugId,
|
||||
methodName, methodBody);
|
||||
}
|
||||
|
||||
virtual void updateScriptBinding(DebugId debugId,
|
||||
@@ -501,11 +197,11 @@ protected:
|
||||
const QString &scriptCode)
|
||||
{
|
||||
if (unsyncronizableChanges
|
||||
== QmlJSLiveTextPreview::NoUnsyncronizableChanges) {
|
||||
== QmlLiveTextPreview::NoUnsyncronizableChanges) {
|
||||
if (propertyName == QLatin1String("id")) {
|
||||
unsyncronizableElementName = propertyName;
|
||||
unsyncronizableChanges
|
||||
= QmlJSLiveTextPreview::AttributeChangeWarning;
|
||||
= QmlLiveTextPreview::AttributeChangeWarning;
|
||||
unsyncronizableChangeLine
|
||||
= parentDefinition->firstSourceLocation().startLine;
|
||||
unsyncronizableChangeColumn
|
||||
@@ -518,7 +214,7 @@ protected:
|
||||
if (isLiteral)
|
||||
expr = castToLiteral(scriptCode, scriptBinding);
|
||||
appliedChangesToViewer = true;
|
||||
m_clientProxy->setBindingForObject(
|
||||
m_inspectorAdapter->engineClient()->setBindingForObject(
|
||||
debugId, propertyName, expr,
|
||||
isLiteral, document()->fileName(),
|
||||
scriptBinding->firstSourceLocation().startLine);
|
||||
@@ -527,13 +223,13 @@ protected:
|
||||
virtual void resetBindingForObject(int debugId, const QString &propertyName)
|
||||
{
|
||||
appliedChangesToViewer = true;
|
||||
m_clientProxy->resetBindingForObject(debugId, propertyName);
|
||||
m_inspectorAdapter->engineClient()->resetBindingForObject(debugId, propertyName);
|
||||
}
|
||||
|
||||
virtual void removeObject(int debugId)
|
||||
{
|
||||
appliedChangesToViewer = true;
|
||||
m_clientProxy->destroyQmlObject(debugId);
|
||||
m_inspectorAdapter->toolsClient()->destroyQmlObject(debugId);
|
||||
}
|
||||
|
||||
virtual void createObject(const QString &qmlText, DebugId ref,
|
||||
@@ -543,18 +239,18 @@ protected:
|
||||
{
|
||||
appliedChangesToViewer = true;
|
||||
referenceRefreshRequired = true;
|
||||
m_clientProxy->createQmlObject(qmlText, ref, importList, filename, order);
|
||||
m_inspectorAdapter->toolsClient()->createQmlObject(qmlText, ref, importList, filename, order);
|
||||
}
|
||||
|
||||
virtual void reparentObject(int debugId, int newParent)
|
||||
{
|
||||
appliedChangesToViewer = true;
|
||||
m_clientProxy->reparentQmlObject(debugId, newParent);
|
||||
m_inspectorAdapter->toolsClient()->reparentQmlObject(debugId, newParent);
|
||||
}
|
||||
|
||||
void notifyUnsyncronizableElementChange(UiObjectMember *parent)
|
||||
{
|
||||
if (unsyncronizableChanges == QmlJSLiveTextPreview::NoUnsyncronizableChanges) {
|
||||
if (unsyncronizableChanges == QmlLiveTextPreview::NoUnsyncronizableChanges) {
|
||||
UiObjectDefinition *parentDefinition = cast<UiObjectDefinition *>(parent);
|
||||
if (parentDefinition && parentDefinition->qualifiedTypeNameId
|
||||
&& !parentDefinition->qualifiedTypeNameId->name.isEmpty())
|
||||
@@ -562,7 +258,7 @@ protected:
|
||||
unsyncronizableElementName
|
||||
= parentDefinition->qualifiedTypeNameId->name.toString();
|
||||
unsyncronizableChanges
|
||||
= QmlJSLiveTextPreview::ElementChangeWarning;
|
||||
= QmlLiveTextPreview::ElementChangeWarning;
|
||||
unsyncronizableChangeLine
|
||||
= parentDefinition->firstSourceLocation().startLine;
|
||||
unsyncronizableChangeColumn
|
||||
@@ -572,30 +268,294 @@ protected:
|
||||
}
|
||||
|
||||
public:
|
||||
UpdateInspector(ClientProxy *clientProxy)
|
||||
UpdateInspector(QmlInspectorAdapter *inspectorAdapter)
|
||||
: appliedChangesToViewer(false)
|
||||
, referenceRefreshRequired(false)
|
||||
, unsyncronizableChanges(QmlJSLiveTextPreview::NoUnsyncronizableChanges)
|
||||
, m_clientProxy(clientProxy)
|
||||
, unsyncronizableChanges(QmlLiveTextPreview::NoUnsyncronizableChanges)
|
||||
, m_inspectorAdapter(inspectorAdapter)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool appliedChangesToViewer;
|
||||
bool referenceRefreshRequired;
|
||||
QString unsyncronizableElementName;
|
||||
QmlJSLiveTextPreview::UnsyncronizableChangeType unsyncronizableChanges;
|
||||
QmlLiveTextPreview::UnsyncronizableChangeType unsyncronizableChanges;
|
||||
unsigned unsyncronizableChangeLine;
|
||||
unsigned unsyncronizableChangeColumn;
|
||||
ClientProxy *m_clientProxy;
|
||||
QmlInspectorAdapter *m_inspectorAdapter;
|
||||
|
||||
};
|
||||
|
||||
void QmlJSLiveTextPreview::documentChanged(QmlJS::Document::Ptr doc)
|
||||
bool MapObjectWithDebugReference::visit(UiObjectDefinition *ast)
|
||||
{
|
||||
if (doc->fileName() != m_previousDoc->fileName() || m_clientProxy.isNull())
|
||||
if (lookupObjects.contains(ast))
|
||||
activated++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MapObjectWithDebugReference::visit(UiObjectBinding *ast)
|
||||
{
|
||||
if (lookupObjects.contains(ast))
|
||||
activated++;
|
||||
return true;
|
||||
}
|
||||
|
||||
void MapObjectWithDebugReference::endVisit(UiObjectDefinition *ast)
|
||||
{
|
||||
process(ast);
|
||||
if (lookupObjects.contains(ast))
|
||||
activated--;
|
||||
}
|
||||
|
||||
void MapObjectWithDebugReference::endVisit(UiObjectBinding *ast)
|
||||
{
|
||||
process(ast);
|
||||
if (lookupObjects.contains(ast))
|
||||
activated--;
|
||||
}
|
||||
|
||||
void MapObjectWithDebugReference::process(UiObjectMember *ast)
|
||||
{
|
||||
if (lookupObjects.isEmpty() || activated) {
|
||||
SourceLocation loc = ast->firstSourceLocation();
|
||||
QHash<QPair<int, int>, DebugIdList>::const_iterator it
|
||||
= ids.constFind(qMakePair<int, int>(loc.startLine, loc.startColumn));
|
||||
if (it != ids.constEnd())
|
||||
result[ast].append(*it);
|
||||
}
|
||||
}
|
||||
|
||||
void MapObjectWithDebugReference::process(UiObjectBinding *ast)
|
||||
{
|
||||
if (lookupObjects.isEmpty() || activated) {
|
||||
SourceLocation loc = ast->qualifiedTypeNameId->identifierToken;
|
||||
QHash<QPair<int, int>, DebugIdList>::const_iterator it
|
||||
= ids.constFind(qMakePair<int, int>(loc.startLine, loc.startColumn));
|
||||
if (it != ids.constEnd())
|
||||
result[ast].append(*it);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Manages a Qml/JS document for the inspector
|
||||
*/
|
||||
QmlLiveTextPreview::QmlLiveTextPreview(const QmlJS::Document::Ptr &doc,
|
||||
const QmlJS::Document::Ptr &initDoc,
|
||||
QmlInspectorAdapter *inspectorAdapter,
|
||||
QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_previousDoc(doc)
|
||||
, m_initialDoc(initDoc)
|
||||
, m_applyChangesToQmlInspector(true)
|
||||
, m_inspectorAdapter(inspectorAdapter)
|
||||
, m_nodeForOffset(0)
|
||||
, m_updateNodeForOffset(false)
|
||||
{
|
||||
QTC_CHECK(doc->fileName() == initDoc->fileName());
|
||||
|
||||
QmlJS::ModelManagerInterface *modelManager
|
||||
= QmlJS::ModelManagerInterface::instance();
|
||||
|
||||
connect(modelManager, SIGNAL(documentChangedOnDisk(QmlJS::Document::Ptr)),
|
||||
SLOT(documentChanged(QmlJS::Document::Ptr)));
|
||||
|
||||
connect(m_inspectorAdapter->agent(), SIGNAL(objectTreeUpdated()),
|
||||
SLOT(updateDebugIds()));
|
||||
}
|
||||
|
||||
void QmlLiveTextPreview::associateEditor(Core::IEditor *editor)
|
||||
{
|
||||
using namespace TextEditor;
|
||||
if (editor->id() == QmlJSEditor::Constants::C_QMLJSEDITOR_ID) {
|
||||
QTC_ASSERT(QLatin1String(editor->widget()->metaObject()->className()) ==
|
||||
QLatin1String("QmlJSEditor::QmlJSTextEditorWidget"),
|
||||
return);
|
||||
|
||||
BaseTextEditorWidget *editWidget
|
||||
= qobject_cast<BaseTextEditorWidget*>(editor->widget());
|
||||
QTC_ASSERT(editWidget, return);
|
||||
|
||||
if (!m_editors.contains(editWidget)) {
|
||||
m_editors << editWidget;
|
||||
if (m_inspectorAdapter)
|
||||
connect(editWidget,
|
||||
SIGNAL(selectedElementsChanged(QList<int>,QString)),
|
||||
SLOT(changeSelectedElements(QList<int>,QString)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QmlLiveTextPreview::unassociateEditor(Core::IEditor *oldEditor)
|
||||
{
|
||||
using namespace TextEditor;
|
||||
if (oldEditor && oldEditor->id()
|
||||
== QmlJSEditor::Constants::C_QMLJSEDITOR_ID) {
|
||||
BaseTextEditorWidget *editWidget
|
||||
= qobject_cast<BaseTextEditorWidget*>(oldEditor->widget());
|
||||
QTC_ASSERT(editWidget, return);
|
||||
|
||||
if (m_editors.contains(editWidget)) {
|
||||
m_editors.removeOne(editWidget);
|
||||
disconnect(editWidget, 0, this, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QmlLiveTextPreview::resetInitialDoc(const QmlJS::Document::Ptr &doc)
|
||||
{
|
||||
m_initialDoc = doc;
|
||||
m_previousDoc = doc;
|
||||
m_createdObjects.clear();
|
||||
m_debugIds.clear();
|
||||
m_docWithUnappliedChanges.clear();
|
||||
}
|
||||
|
||||
void QmlLiveTextPreview::setApplyChangesToQmlInspector(bool applyChanges)
|
||||
{
|
||||
if (applyChanges && !m_applyChangesToQmlInspector) {
|
||||
if (m_docWithUnappliedChanges) {
|
||||
m_applyChangesToQmlInspector = true;
|
||||
documentChanged(m_docWithUnappliedChanges);
|
||||
}
|
||||
}
|
||||
|
||||
m_applyChangesToQmlInspector = applyChanges;
|
||||
}
|
||||
|
||||
static QList<int> findRootObjectRecursive(const QmlDebugObjectReference &object,
|
||||
const Document::Ptr &doc)
|
||||
{
|
||||
QList<int> result;
|
||||
if (object.className() == doc->componentName())
|
||||
result += object.debugId();
|
||||
|
||||
foreach (const QmlDebugObjectReference &it, object.children()) {
|
||||
result += findRootObjectRecursive(it, doc);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void QmlLiveTextPreview::updateDebugIds()
|
||||
{
|
||||
if (!m_initialDoc->qmlProgram())
|
||||
return;
|
||||
|
||||
bool experimentalWarningShown = false;
|
||||
DebugIdHash::const_iterator it
|
||||
= m_inspectorAdapter->agent()->debugIdHash().constFind(
|
||||
qMakePair<QString, int>(m_initialDoc->fileName(), 0));
|
||||
if (it != m_inspectorAdapter->agent()->debugIdHash().constEnd()) {
|
||||
// Map all the object that comes from the document as it has been loaded
|
||||
// by the server.
|
||||
const QmlJS::Document::Ptr &doc = m_initialDoc;
|
||||
|
||||
MapObjectWithDebugReference visitor;
|
||||
visitor.ids = (*it);
|
||||
visitor.filename = doc->fileName();
|
||||
doc->qmlProgram()->accept(&visitor);
|
||||
|
||||
m_debugIds = visitor.result;
|
||||
if (doc != m_previousDoc) {
|
||||
Delta delta;
|
||||
m_debugIds = delta(doc, m_previousDoc, m_debugIds);
|
||||
}
|
||||
}
|
||||
|
||||
const QmlJS::Document::Ptr &doc = m_previousDoc;
|
||||
if (!doc->qmlProgram())
|
||||
return;
|
||||
|
||||
// Map the root nodes of the document.
|
||||
if (doc->qmlProgram()->members && doc->qmlProgram()->members->member) {
|
||||
UiObjectMember *root = doc->qmlProgram()->members->member;
|
||||
QList<int> r;
|
||||
foreach (const QmlDebugObjectReference& it,
|
||||
m_inspectorAdapter->agent()->rootObjects()) {
|
||||
r += findRootObjectRecursive(it, doc);
|
||||
}
|
||||
if (!r.isEmpty())
|
||||
m_debugIds[root] += r;
|
||||
}
|
||||
|
||||
// Map the node of the later created objects.
|
||||
for (QHash<Document::Ptr,QSet<UiObjectMember*> >::const_iterator it
|
||||
= m_createdObjects.constBegin();
|
||||
it != m_createdObjects.constEnd(); ++it) {
|
||||
|
||||
const QmlJS::Document::Ptr &doc = it.key();
|
||||
|
||||
DebugIdHash::const_iterator id_it = m_inspectorAdapter->agent()->debugIdHash().constFind(
|
||||
qMakePair<QString, int>(doc->fileName(), doc->editorRevision()));
|
||||
if (id_it == m_inspectorAdapter->agent()->debugIdHash().constEnd())
|
||||
continue;
|
||||
|
||||
MapObjectWithDebugReference visitor;
|
||||
visitor.ids = *id_it;
|
||||
visitor.filename = doc->fileName();
|
||||
visitor.lookupObjects = it.value();
|
||||
doc->qmlProgram()->accept(&visitor);
|
||||
|
||||
Delta::DebugIdMap debugIds = visitor.result;
|
||||
if (doc != m_previousDoc) {
|
||||
Delta delta;
|
||||
debugIds = delta(doc, m_previousDoc, debugIds);
|
||||
}
|
||||
for (Delta::DebugIdMap::const_iterator it2 = debugIds.constBegin();
|
||||
it2 != debugIds.constEnd(); ++it2) {
|
||||
m_debugIds[it2.key()] += it2.value();
|
||||
}
|
||||
}
|
||||
if (m_updateNodeForOffset)
|
||||
changeSelectedElements(m_lastOffsets, QString());
|
||||
}
|
||||
|
||||
void QmlLiveTextPreview::changeSelectedElements(QList<int> offsets,
|
||||
const QString &wordAtCursor)
|
||||
{
|
||||
if (m_editors.isEmpty() || !m_previousDoc)
|
||||
return;
|
||||
|
||||
m_updateNodeForOffset = false;
|
||||
m_lastOffsets = offsets;
|
||||
QmlDebugObjectReference objectRefUnderCursor;
|
||||
objectRefUnderCursor
|
||||
= m_inspectorAdapter->agent()->objectForId(wordAtCursor);
|
||||
|
||||
QList<int> selectedReferences;
|
||||
bool containsReferenceUnderCursor = false;
|
||||
|
||||
foreach (int offset, offsets) {
|
||||
if (offset >= 0) {
|
||||
QList<int> list = objectReferencesForOffset(offset);
|
||||
|
||||
if (!containsReferenceUnderCursor
|
||||
&& objectRefUnderCursor.debugId() != -1) {
|
||||
foreach (int id, list) {
|
||||
if (id == objectRefUnderCursor.debugId()) {
|
||||
containsReferenceUnderCursor = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
selectedReferences << list;
|
||||
}
|
||||
}
|
||||
|
||||
// fallback: use ref under cursor if nothing else is found
|
||||
if (selectedReferences.isEmpty()
|
||||
&& !containsReferenceUnderCursor
|
||||
&& objectRefUnderCursor.debugId() != -1) {
|
||||
selectedReferences << objectRefUnderCursor.debugId();
|
||||
}
|
||||
|
||||
if (!selectedReferences.isEmpty())
|
||||
emit selectedItemsChanged(selectedReferences);
|
||||
}
|
||||
|
||||
void QmlLiveTextPreview::documentChanged(QmlJS::Document::Ptr doc)
|
||||
{
|
||||
if (doc->fileName() != m_previousDoc->fileName())
|
||||
return;
|
||||
|
||||
if (m_applyChangesToQmlInspector) {
|
||||
m_docWithUnappliedChanges.clear();
|
||||
@@ -603,21 +563,14 @@ void QmlJSLiveTextPreview::documentChanged(QmlJS::Document::Ptr doc)
|
||||
if (doc && m_previousDoc && doc->fileName() == m_previousDoc->fileName()
|
||||
&& doc->qmlProgram() && m_previousDoc->qmlProgram())
|
||||
{
|
||||
UpdateInspector delta(m_clientProxy.data());
|
||||
UpdateInspector delta(m_inspectorAdapter);
|
||||
m_debugIds = delta(m_previousDoc, doc, m_debugIds);
|
||||
|
||||
if (delta.referenceRefreshRequired)
|
||||
m_clientProxy.data()->refreshObjectTree();
|
||||
m_inspectorAdapter->agent()->refreshObjectTree();
|
||||
|
||||
if (InspectorUi::instance()->showExperimentalWarning()
|
||||
&& delta.appliedChangesToViewer) {
|
||||
showExperimentalWarning();
|
||||
experimentalWarningShown = true;
|
||||
InspectorUi::instance()->setShowExperimentalWarning(false);
|
||||
}
|
||||
|
||||
if (delta.unsyncronizableChanges != NoUnsyncronizableChanges
|
||||
&& !experimentalWarningShown)
|
||||
if (delta.unsyncronizableChanges != NoUnsyncronizableChanges)
|
||||
showSyncWarning(delta.unsyncronizableChanges,
|
||||
delta.unsyncronizableElementName,
|
||||
delta.unsyncronizableChangeLine,
|
||||
@@ -627,30 +580,44 @@ void QmlJSLiveTextPreview::documentChanged(QmlJS::Document::Ptr doc)
|
||||
if (!delta.newObjects.isEmpty())
|
||||
m_createdObjects[doc] += delta.newObjects;
|
||||
|
||||
m_clientProxy.data()->clearComponentCache();
|
||||
m_inspectorAdapter->toolsClient()->clearComponentCache();
|
||||
}
|
||||
} else {
|
||||
m_docWithUnappliedChanges = doc;
|
||||
}
|
||||
}
|
||||
|
||||
void QmlJSLiveTextPreview::showExperimentalWarning()
|
||||
QList<int> QmlLiveTextPreview::objectReferencesForOffset(quint32 offset)
|
||||
{
|
||||
foreach (QWeakPointer<TextEditor::BaseTextEditorWidget> editor, m_editors)
|
||||
if (editor) {
|
||||
Core::InfoBarEntry info(
|
||||
Constants::INFO_EXPERIMENTAL,
|
||||
tr("You changed a QML file in Live Preview mode, which "
|
||||
"modifies the running QML application. In case of "
|
||||
"unexpected behavior, please reload the QML "
|
||||
"application."));
|
||||
info.setCustomButtonInfo(tr("Disable Live Preview"), this,
|
||||
SLOT(disableLivePreview()));
|
||||
editor.data()->editorDocument()->infoBar()->addInfo(info);
|
||||
QList<int> result;
|
||||
QHashIterator<QmlJS::AST::UiObjectMember*, QList<int> > iter(m_debugIds);
|
||||
QmlJS::AST::UiObjectMember *possibleNode = 0;
|
||||
while (iter.hasNext()) {
|
||||
iter.next();
|
||||
QmlJS::AST::UiObjectMember *member = iter.key();
|
||||
quint32 startOffset = member->firstSourceLocation().offset;
|
||||
quint32 endOffset = member->lastSourceLocation().offset;
|
||||
if (startOffset <= offset && offset <= endOffset) {
|
||||
if (!possibleNode)
|
||||
possibleNode = member;
|
||||
if (possibleNode->firstSourceLocation().offset <= startOffset &&
|
||||
endOffset <= possibleNode->lastSourceLocation().offset)
|
||||
possibleNode = member;
|
||||
}
|
||||
}
|
||||
if (possibleNode) {
|
||||
if (possibleNode != m_nodeForOffset) {
|
||||
//We have found a better match, set flag so that we can
|
||||
//query again to check if this is the best match for the offset
|
||||
m_updateNodeForOffset = true;
|
||||
m_nodeForOffset = possibleNode;
|
||||
}
|
||||
result = m_debugIds.value(possibleNode);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void QmlJSLiveTextPreview::showSyncWarning(
|
||||
void QmlLiveTextPreview::showSyncWarning(
|
||||
UnsyncronizableChangeType unsyncronizableChangeType,
|
||||
const QString &elementName, unsigned line, unsigned column)
|
||||
{
|
||||
@@ -666,87 +633,22 @@ void QmlJSLiveTextPreview::showSyncWarning(
|
||||
"changed without reloading the QML application. ")
|
||||
.arg(elementName, QString::number(line), QString::number(column));
|
||||
break;
|
||||
case QmlJSLiveTextPreview::NoUnsyncronizableChanges:
|
||||
case QmlLiveTextPreview::NoUnsyncronizableChanges:
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
errorMessage.append(tr("You can continue debugging, but behavior can be unexpected."));
|
||||
|
||||
foreach (QWeakPointer<TextEditor::BaseTextEditorWidget> editor, m_editors) {
|
||||
foreach (TextEditor::BaseTextEditorWidget *editor, m_editors) {
|
||||
if (editor) {
|
||||
Core::InfoBar *infoBar = editor.data()->editorDocument()->infoBar();
|
||||
Core::InfoBar *infoBar = editor->editorDocument()->infoBar();
|
||||
infoBar->addInfo(Core::InfoBarEntry(
|
||||
QLatin1String(Constants::INFO_OUT_OF_SYNC),
|
||||
QLatin1String("Debugger.Inspector.OutOfSyncWarning"),
|
||||
errorMessage));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QmlJSLiveTextPreview::reloadQmlViewer()
|
||||
{
|
||||
foreach (QWeakPointer<TextEditor::BaseTextEditorWidget> editor, m_editors) {
|
||||
if (editor) {
|
||||
Core::InfoBar *infoBar = editor.data()->editorDocument()->infoBar();
|
||||
infoBar->removeInfo(Constants::INFO_OUT_OF_SYNC);
|
||||
}
|
||||
}
|
||||
emit reloadQmlViewerRequested();
|
||||
}
|
||||
|
||||
void QmlJSLiveTextPreview::disableLivePreview()
|
||||
{
|
||||
foreach (QWeakPointer<TextEditor::BaseTextEditorWidget> editor, m_editors) {
|
||||
if (editor) {
|
||||
Core::InfoBar *infoBar = editor.data()->editorDocument()->infoBar();
|
||||
infoBar->removeInfo(Constants::INFO_OUT_OF_SYNC);
|
||||
}
|
||||
}
|
||||
emit disableLivePreviewRequested();
|
||||
}
|
||||
|
||||
void QmlJSLiveTextPreview::setApplyChangesToQmlInspector(bool applyChanges)
|
||||
{
|
||||
if (applyChanges && !m_applyChangesToQmlInspector) {
|
||||
if (m_docWithUnappliedChanges) {
|
||||
m_applyChangesToQmlInspector = true;
|
||||
documentChanged(m_docWithUnappliedChanges);
|
||||
}
|
||||
}
|
||||
|
||||
m_applyChangesToQmlInspector = applyChanges;
|
||||
}
|
||||
|
||||
void QmlJSLiveTextPreview::setClientProxy(ClientProxy *clientProxy)
|
||||
{
|
||||
if (m_clientProxy.data()) {
|
||||
disconnect(m_clientProxy.data(), SIGNAL(objectTreeUpdated()),
|
||||
this, SLOT(updateDebugIds()));
|
||||
}
|
||||
|
||||
m_clientProxy = clientProxy;
|
||||
|
||||
if (m_clientProxy.data()) {
|
||||
connect(m_clientProxy.data(), SIGNAL(objectTreeUpdated()),
|
||||
SLOT(updateDebugIds()));
|
||||
|
||||
foreach (QWeakPointer<TextEditor::BaseTextEditorWidget> editWidget,
|
||||
m_editors)
|
||||
if (editWidget)
|
||||
connect(editWidget.data(),
|
||||
SIGNAL(selectedElementsChanged(QList<int>,QString)),
|
||||
this,
|
||||
SLOT(changeSelectedElements(QList<int>,QString)));
|
||||
} else {
|
||||
foreach (QWeakPointer<TextEditor::BaseTextEditorWidget> editWidget,
|
||||
m_editors)
|
||||
if (editWidget)
|
||||
disconnect(editWidget.data(),
|
||||
SIGNAL(selectedElementsChanged(QList<int>,QString)),
|
||||
this,
|
||||
SLOT(changeSelectedElements(QList<int>,QString)));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSInspector
|
||||
} // namespace Debugger
|
@@ -30,21 +30,14 @@
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef SCRIPTBINDINGREWRITER_H
|
||||
#define SCRIPTBINDINGREWRITER_H
|
||||
#ifndef QMLLIVETEXTPREVIEW_H
|
||||
#define QMLLIVETEXTPREVIEW_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QWeakPointer>
|
||||
|
||||
#include <texteditor/basetexteditor.h>
|
||||
|
||||
#include <qmldebug/baseenginedebugclient.h>
|
||||
#include <qmljs/parser/qmljsastfwd_p.h>
|
||||
#include <qmljs/qmljsdocument.h>
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QTextDocument)
|
||||
|
||||
using namespace QmlDebug;
|
||||
|
||||
namespace Core {
|
||||
class IEditor;
|
||||
}
|
||||
@@ -53,41 +46,28 @@ namespace QmlJS {
|
||||
class ModelManagerInterface;
|
||||
}
|
||||
|
||||
namespace QmlJSInspector {
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
class ClientProxy;
|
||||
class UpdateInspector;
|
||||
class QmlInspectorAdapter;
|
||||
|
||||
|
||||
class QmlJSLiveTextPreview : public QObject
|
||||
class QmlLiveTextPreview : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit QmlJSLiveTextPreview(const QmlJS::Document::Ptr &doc,
|
||||
const QmlJS::Document::Ptr &initDoc,
|
||||
ClientProxy *clientProxy,
|
||||
QObject *parent = 0);
|
||||
//void updateDocuments();
|
||||
QmlLiveTextPreview(const QmlJS::Document::Ptr &doc,
|
||||
const QmlJS::Document::Ptr &initDoc,
|
||||
QmlInspectorAdapter *inspectorAdapter,
|
||||
QObject *parent = 0);
|
||||
|
||||
void associateEditor(Core::IEditor *editor);
|
||||
void unassociateEditor(Core::IEditor *editor);
|
||||
void setActiveObject(const QmlDebugObjectReference &object);
|
||||
void mapObjectToQml(const QmlDebugObjectReference &object);
|
||||
void resetInitialDoc(const QmlJS::Document::Ptr &doc);
|
||||
|
||||
void setClientProxy(ClientProxy *clientProxy);
|
||||
|
||||
enum UnsyncronizableChangeType {
|
||||
NoUnsyncronizableChanges,
|
||||
AttributeChangeWarning,
|
||||
ElementChangeWarning
|
||||
};
|
||||
|
||||
signals:
|
||||
void selectedItemsChanged(const QList<QmlDebugObjectReference> &objects);
|
||||
void reloadQmlViewerRequested();
|
||||
void disableLivePreviewRequested();
|
||||
void selectedItemsChanged(const QList<int> &debugIds);
|
||||
|
||||
public slots:
|
||||
void setApplyChangesToQmlInspector(bool applyChanges);
|
||||
@@ -96,17 +76,18 @@ public slots:
|
||||
private slots:
|
||||
void changeSelectedElements(QList<int> offsets, const QString &wordAtCursor);
|
||||
void documentChanged(QmlJS::Document::Ptr doc);
|
||||
void disableLivePreview();
|
||||
void reloadQmlViewer();
|
||||
|
||||
private:
|
||||
enum UnsyncronizableChangeType {
|
||||
NoUnsyncronizableChanges,
|
||||
AttributeChangeWarning,
|
||||
ElementChangeWarning
|
||||
};
|
||||
|
||||
QList<int> objectReferencesForOffset(quint32 offset);
|
||||
QVariant castToLiteral(const QString &expression,
|
||||
QmlJS::AST::UiScriptBinding *scriptBinding);
|
||||
void showSyncWarning(UnsyncronizableChangeType unsyncronizableChangeType,
|
||||
const QString &elementName,
|
||||
unsigned line, unsigned column);
|
||||
void showExperimentalWarning();
|
||||
|
||||
private:
|
||||
QHash<QmlJS::AST::UiObjectMember*, QList<int> > m_debugIds;
|
||||
@@ -114,20 +95,20 @@ private:
|
||||
|
||||
QmlJS::Document::Ptr m_previousDoc;
|
||||
QmlJS::Document::Ptr m_initialDoc; //the document that was loaded by the server
|
||||
QString m_filename;
|
||||
|
||||
QList<QWeakPointer<TextEditor::BaseTextEditorWidget> > m_editors;
|
||||
QList<QPointer<TextEditor::BaseTextEditorWidget> > m_editors;
|
||||
|
||||
bool m_applyChangesToQmlInspector;
|
||||
QmlJS::Document::Ptr m_docWithUnappliedChanges;
|
||||
QWeakPointer<ClientProxy> m_clientProxy;
|
||||
QmlInspectorAdapter *m_inspectorAdapter;
|
||||
QList<int> m_lastOffsets;
|
||||
QmlJS::AST::UiObjectMember *m_nodeForOffset;
|
||||
bool m_updateNodeForOffset;
|
||||
|
||||
friend class UpdateInspector;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSInspector
|
||||
} // namespace Debugger
|
||||
|
||||
#endif // SCRIPTBINDINGREWRITER_H
|
||||
#endif // QMLLIVETEXTPREVIEW_H
|
@@ -172,6 +172,10 @@ WatchModel::WatchModel(WatchHandler *handler, WatchType type)
|
||||
m_root->iname = "tooltip";
|
||||
m_root->name = WatchHandler::tr("Tooltip");
|
||||
break;
|
||||
case InspectWatch:
|
||||
m_root->iname = "inspect";
|
||||
m_root->name = WatchHandler::tr("Inspector");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -576,7 +580,7 @@ bool WatchModel::canFetchMore(const QModelIndex &index) const
|
||||
{
|
||||
WatchItem *item = watchItem(index);
|
||||
QTC_ASSERT(item, return false);
|
||||
return index.isValid() && m_handler->m_contentsValid && !m_fetchTriggered.contains(item->iname);
|
||||
return index.isValid() && contentIsValid() && !m_fetchTriggered.contains(item->iname);
|
||||
}
|
||||
|
||||
void WatchModel::fetchMore(const QModelIndex &index)
|
||||
@@ -713,6 +717,14 @@ int WatchModel::itemFormat(const WatchData &data) const
|
||||
return theTypeFormats.value(stripForFormat(data.type), -1);
|
||||
}
|
||||
|
||||
bool WatchModel::contentIsValid() const
|
||||
{
|
||||
// inspector doesn't follow normal beginCycle()/endCycle()
|
||||
if (m_type == InspectWatch)
|
||||
return true;
|
||||
return m_handler->m_contentsValid;
|
||||
}
|
||||
|
||||
static inline QString expression(const WatchItem *item)
|
||||
{
|
||||
if (!item->exp.isEmpty())
|
||||
@@ -812,7 +824,7 @@ QVariant WatchModel::data(const QModelIndex &idx, int role) const
|
||||
static const QVariant red(QColor(200, 0, 0));
|
||||
static const QVariant gray(QColor(140, 140, 140));
|
||||
switch (idx.column()) {
|
||||
case 1: return (!data.valueEnabled || !m_handler->m_contentsValid) ? gray
|
||||
case 1: return (!data.valueEnabled || !contentIsValid()) ? gray
|
||||
: data.changed ? red : QVariant();
|
||||
}
|
||||
break;
|
||||
@@ -927,7 +939,7 @@ bool WatchModel::setData(const QModelIndex &index, const QVariant &value, int ro
|
||||
|
||||
Qt::ItemFlags WatchModel::flags(const QModelIndex &idx) const
|
||||
{
|
||||
if (!m_handler->m_contentsValid)
|
||||
if (!contentIsValid())
|
||||
return Qt::ItemFlags();
|
||||
|
||||
if (!idx.isValid())
|
||||
@@ -1276,6 +1288,7 @@ WatchHandler::WatchHandler(DebuggerEngine *engine)
|
||||
m_locals = new WatchModel(this, LocalsWatch);
|
||||
m_watchers = new WatchModel(this, WatchersWatch);
|
||||
m_tooltips = new WatchModel(this, TooltipsWatch);
|
||||
m_inspect = new WatchModel(this, InspectWatch);
|
||||
|
||||
m_contentsValid = false;
|
||||
m_resetLocationScheduled = false;
|
||||
@@ -1294,6 +1307,7 @@ void WatchHandler::beginCycle(bool fullCycle)
|
||||
m_locals->beginCycle(fullCycle);
|
||||
m_watchers->beginCycle(fullCycle);
|
||||
m_tooltips->beginCycle(fullCycle);
|
||||
// don't sync m_inspect here: It's updated on it's own
|
||||
}
|
||||
|
||||
void WatchHandler::endCycle()
|
||||
@@ -1309,6 +1323,16 @@ void WatchHandler::endCycle()
|
||||
updateWatchersWindow();
|
||||
}
|
||||
|
||||
void WatchHandler::beginCycle(WatchType type, bool fullCycle)
|
||||
{
|
||||
model(type)->beginCycle(fullCycle);
|
||||
}
|
||||
|
||||
void WatchHandler::endCycle(WatchType type)
|
||||
{
|
||||
model(type)->endCycle();
|
||||
}
|
||||
|
||||
void WatchHandler::cleanup()
|
||||
{
|
||||
m_expandedINames.clear();
|
||||
@@ -1316,10 +1340,12 @@ void WatchHandler::cleanup()
|
||||
m_return->reinitialize();
|
||||
m_locals->reinitialize();
|
||||
m_tooltips->reinitialize();
|
||||
m_inspect->reinitialize();
|
||||
m_return->m_fetchTriggered.clear();
|
||||
m_locals->m_fetchTriggered.clear();
|
||||
m_watchers->m_fetchTriggered.clear();
|
||||
m_tooltips->m_fetchTriggered.clear();
|
||||
m_inspect->m_fetchTriggered.clear();
|
||||
#if 1
|
||||
for (EditHandlers::ConstIterator it = m_editHandlers.begin();
|
||||
it != m_editHandlers.end(); ++it) {
|
||||
@@ -1336,6 +1362,7 @@ void WatchHandler::emitAllChanged()
|
||||
m_locals->emitAllChanged();
|
||||
m_watchers->emitAllChanged();
|
||||
m_tooltips->emitAllChanged();
|
||||
m_inspect->emitAllChanged();
|
||||
}
|
||||
|
||||
void WatchHandler::insertData(const WatchData &data)
|
||||
@@ -1347,9 +1374,10 @@ void WatchHandler::insertData(const WatchData &data)
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.isSomethingNeeded() && data.iname.contains('.')) {
|
||||
if (data.isSomethingNeeded() && data.iname.contains(".")) {
|
||||
MODEL_DEBUG("SOMETHING NEEDED: " << data.toString());
|
||||
if (!m_engine->isSynchronous()) {
|
||||
if (!m_engine->isSynchronous()
|
||||
|| data.iname.startsWith("inspect.")) {
|
||||
WatchModel *model = modelForIName(data.iname);
|
||||
QTC_ASSERT(model, return);
|
||||
model->insertData(data);
|
||||
@@ -1381,6 +1409,7 @@ void WatchHandler::reinsertAllData()
|
||||
m_watchers->reinsertAllData();
|
||||
m_tooltips->reinsertAllData();
|
||||
m_return->reinsertAllData();
|
||||
m_inspect->reinsertAllData();
|
||||
}
|
||||
|
||||
// Bulk-insertion
|
||||
@@ -1685,6 +1714,7 @@ WatchModel *WatchHandler::model(WatchType type) const
|
||||
case LocalsWatch: return m_locals;
|
||||
case WatchersWatch: return m_watchers;
|
||||
case TooltipsWatch: return m_tooltips;
|
||||
case InspectWatch: return m_inspect;
|
||||
}
|
||||
QTC_CHECK(false);
|
||||
return 0;
|
||||
@@ -1700,6 +1730,8 @@ WatchModel *WatchHandler::modelForIName(const QByteArray &iname) const
|
||||
return m_tooltips;
|
||||
if (iname.startsWith("watch"))
|
||||
return m_watchers;
|
||||
if (iname.startsWith("inspect"))
|
||||
return m_inspect;
|
||||
QTC_ASSERT(false, qDebug() << "INAME: " << iname);
|
||||
return 0;
|
||||
}
|
||||
@@ -1746,6 +1778,7 @@ void WatchHandler::setFormat(const QByteArray &type0, int format)
|
||||
m_locals->emitDataChanged(1);
|
||||
m_watchers->emitDataChanged(1);
|
||||
m_tooltips->emitDataChanged(1);
|
||||
m_inspect->emitDataChanged(1);
|
||||
}
|
||||
|
||||
int WatchHandler::format(const QByteArray &iname) const
|
||||
@@ -1905,6 +1938,7 @@ void WatchHandler::resetLocation()
|
||||
m_locals->invalidateAll();
|
||||
m_watchers->invalidateAll();
|
||||
m_tooltips->invalidateAll();
|
||||
m_inspect->invalidateAll();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1914,6 +1948,14 @@ bool WatchHandler::isValidToolTip(const QByteArray &iname) const
|
||||
return item && !item->type.trimmed().isEmpty();
|
||||
}
|
||||
|
||||
void WatchHandler::setCurrentModelIndex(WatchType modelType,
|
||||
const QModelIndex &index)
|
||||
{
|
||||
if (WatchModel *m = model(modelType)) {
|
||||
emit m->setCurrentIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
QHash<QByteArray, int> WatchHandler::watcherNames()
|
||||
{
|
||||
return theWatcherNames;
|
||||
|
@@ -55,7 +55,8 @@ enum WatchType
|
||||
ReturnWatch,
|
||||
LocalsWatch,
|
||||
WatchersWatch,
|
||||
TooltipsWatch
|
||||
TooltipsWatch,
|
||||
InspectWatch
|
||||
};
|
||||
|
||||
enum IntegerFormat
|
||||
@@ -78,6 +79,9 @@ public:
|
||||
virtual int rowCount(const QModelIndex &idx = QModelIndex()) const;
|
||||
virtual int columnCount(const QModelIndex &idx) const;
|
||||
|
||||
signals:
|
||||
void setCurrentIndex(const QModelIndex &index);
|
||||
|
||||
private:
|
||||
QVariant data(const QModelIndex &index, int role) const;
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role);
|
||||
@@ -131,6 +135,7 @@ private:
|
||||
DebuggerEngine *engine() const;
|
||||
QString display(const WatchItem *item, int col) const;
|
||||
int itemFormat(const WatchData &data) const;
|
||||
bool contentIsValid() const;
|
||||
int m_generationCounter;
|
||||
|
||||
WatchHandler *m_handler;
|
||||
@@ -157,6 +162,10 @@ public:
|
||||
void beginCycle(bool fullCycle = true); // Called at begin of updateLocals() cycle
|
||||
void updateWatchers(); // Called after locals are fetched
|
||||
void endCycle(); // Called after all results have been received
|
||||
|
||||
void beginCycle(WatchType type, bool fullCycle = true);
|
||||
void endCycle(WatchType type);
|
||||
|
||||
void showEditValue(const WatchData &data);
|
||||
|
||||
void insertData(const WatchData &data);
|
||||
@@ -204,6 +213,8 @@ public:
|
||||
void resetLocation();
|
||||
bool isValidToolTip(const QByteArray &iname) const;
|
||||
|
||||
void setCurrentModelIndex(WatchType modelType, const QModelIndex &index);
|
||||
|
||||
private:
|
||||
friend class WatchModel;
|
||||
|
||||
@@ -230,6 +241,7 @@ private:
|
||||
WatchModel *m_locals;
|
||||
WatchModel *m_watchers;
|
||||
WatchModel *m_tooltips;
|
||||
WatchModel *m_inspect;
|
||||
DebuggerEngine *m_engine;
|
||||
|
||||
int m_watcherCounter;
|
||||
|
@@ -994,11 +994,15 @@ void WatchTreeView::setModel(QAbstractItemModel *model)
|
||||
setRootIsDecorated(true);
|
||||
if (header()) {
|
||||
header()->setDefaultAlignment(Qt::AlignLeft);
|
||||
if (m_type != LocalsType)
|
||||
if (m_type != LocalsType && m_type != InspectType)
|
||||
header()->hide();
|
||||
}
|
||||
|
||||
connect(model, SIGNAL(layoutChanged()), SLOT(resetHelper()));
|
||||
|
||||
QTC_ASSERT(qobject_cast<WatchModel*>(model), return);
|
||||
connect(model, SIGNAL(setCurrentIndex(QModelIndex)),
|
||||
SLOT(setCurrentIndex(QModelIndex)));
|
||||
}
|
||||
|
||||
void WatchTreeView::resetHelper()
|
||||
|
@@ -49,7 +49,7 @@ class WatchTreeView : public BaseTreeView
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Type { ReturnType, LocalsType, TooltipType, WatchersType };
|
||||
enum Type { ReturnType, LocalsType, TooltipType, WatchersType, InspectType };
|
||||
|
||||
explicit WatchTreeView(Type type, QWidget *parent = 0);
|
||||
Type type() const { return m_type; }
|
||||
|
@@ -61,8 +61,7 @@ include(../../qtcreator.pri)
|
||||
|
||||
contains(QT_CONFIG, declarative)|contains(QT_CONFIG, quick1) {
|
||||
SUBDIRS += \
|
||||
plugin_qmlprojectmanager \
|
||||
plugin_qmljsinspector
|
||||
plugin_qmlprojectmanager
|
||||
|
||||
include(../private_headers.pri)
|
||||
exists($${QT_PRIVATE_HEADERS}/QtDeclarative/private/qdeclarativecontext_p.h) {
|
||||
@@ -193,6 +192,7 @@ plugin_debugger.subdir = debugger
|
||||
plugin_debugger.depends = plugin_projectexplorer
|
||||
plugin_debugger.depends += plugin_coreplugin
|
||||
plugin_debugger.depends += plugin_cpptools
|
||||
plugin_debugger.depends += plugin_qmljstools
|
||||
|
||||
plugin_fakevim.subdir = fakevim
|
||||
plugin_fakevim.depends = plugin_coreplugin
|
||||
@@ -264,10 +264,6 @@ plugin_qmldesigner.depends += plugin_qt4projectmanager
|
||||
plugin_qmldesigner.depends += plugin_qmlprojectmanager
|
||||
plugin_qmldesigner.depends += plugin_cpptools
|
||||
|
||||
plugin_qmljsinspector.subdir = qmljsinspector
|
||||
plugin_qmljsinspector.depends += plugin_debugger
|
||||
plugin_qmljsinspector.depends += plugin_qmljstools
|
||||
|
||||
plugin_mercurial.subdir = mercurial
|
||||
plugin_mercurial.depends = plugin_vcsbase
|
||||
plugin_mercurial.depends += plugin_projectexplorer
|
||||
|
@@ -1,26 +0,0 @@
|
||||
<plugin name=\"QmlJSInspector\" version=\"$$QTCREATOR_VERSION\" compatVersion=\"$$QTCREATOR_VERSION\">
|
||||
<vendor>Nokia Corporation</vendor>
|
||||
<copyright>(C) 2011 Nokia Corporation</copyright>
|
||||
<license>
|
||||
Commercial Usage
|
||||
|
||||
Licensees holding valid Qt Commercial licenses may use this plugin in
|
||||
accordance with the Qt Commercial License Agreement provided with the
|
||||
Software or, alternatively, in accordance with the terms contained in
|
||||
a written agreement between you and Nokia.
|
||||
|
||||
GNU Lesser General Public License Usage
|
||||
|
||||
Alternatively, this plugin may be used under the terms of the GNU Lesser
|
||||
General Public License version 2.1 as published by the Free Software
|
||||
Foundation. Please review the following information to
|
||||
ensure the GNU Lesser General Public License version 2.1 requirements
|
||||
will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.</license>
|
||||
<category>Qt Quick</category>
|
||||
<description>Debugger for QML files</description>
|
||||
<url>http://qt.nokia.com</url>
|
||||
<dependencyList>
|
||||
<dependency name=\"Debugger\" version=\"$$QTCREATOR_VERSION\"/>
|
||||
<dependency name=\"QmlJSTools\" version=\"$$QTCREATOR_VERSION\"/>
|
||||
</dependencyList>
|
||||
</plugin>
|
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 735 B |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 3.2 KiB |
@@ -1,810 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "qmljsclientproxy.h"
|
||||
#include "qmltoolsclient.h"
|
||||
#include "declarativetoolsclient.h"
|
||||
#include "qmljsinspector.h"
|
||||
|
||||
#include <qmldebug/qmldebugconstants.h>
|
||||
#include <debugger/debuggerplugin.h>
|
||||
#include <debugger/debuggerrunner.h>
|
||||
#include <debugger/qml/qmlengine.h>
|
||||
#include <debugger/qml/qmladapter.h>
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <projectexplorer/project.h>
|
||||
#include <qmldebug/declarativeenginedebugclient.h>
|
||||
#include <qmldebug/qmlenginedebugclient.h>
|
||||
|
||||
#include <QUrl>
|
||||
#include <QAbstractSocket>
|
||||
|
||||
using namespace QmlJSInspector::Internal;
|
||||
|
||||
ClientProxy::ClientProxy(Debugger::QmlAdapter *adapter, QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_adapter(adapter)
|
||||
, m_engineClient(0)
|
||||
, m_inspectorHelperClient(0)
|
||||
, m_engineQueryId(0)
|
||||
, m_contextQueryId(0)
|
||||
, m_isConnected(false)
|
||||
{
|
||||
connectToServer();
|
||||
}
|
||||
|
||||
ClientProxy::~ClientProxy()
|
||||
{
|
||||
m_adapter.data()->setEngineDebugClient(0);
|
||||
m_adapter.data()->setCurrentSelectedDebugInfo(-1);
|
||||
}
|
||||
|
||||
void ClientProxy::connectToServer()
|
||||
{
|
||||
DeclarativeEngineDebugClient *client1 = new DeclarativeEngineDebugClient(
|
||||
m_adapter.data()->connection());
|
||||
QmlEngineDebugClient *client2 = new QmlEngineDebugClient(
|
||||
m_adapter.data()->connection());
|
||||
|
||||
connect(client1, SIGNAL(newStatus(QmlDebugClient::Status)),
|
||||
SLOT(clientStatusChanged(QmlDebugClient::Status)));
|
||||
connect(client1, SIGNAL(newStatus(QmlDebugClient::Status)),
|
||||
SLOT(engineClientStatusChanged(QmlDebugClient::Status)));
|
||||
|
||||
connect(client2, SIGNAL(newStatus(QmlDebugClient::Status)),
|
||||
SLOT(clientStatusChanged(QmlDebugClient::Status)));
|
||||
connect(client2, SIGNAL(newStatus(QmlDebugClient::Status)),
|
||||
SLOT(engineClientStatusChanged(QmlDebugClient::Status)));
|
||||
|
||||
DeclarativeToolsClient *toolsClient1 = new DeclarativeToolsClient(
|
||||
m_adapter.data()->connection());
|
||||
QmlToolsClient *toolsClient2 = new QmlToolsClient(
|
||||
m_adapter.data()->connection());
|
||||
|
||||
connect(toolsClient1, SIGNAL(connectedStatusChanged(QmlDebugClient::Status)),
|
||||
SLOT(clientStatusChanged(QmlDebugClient::Status)));
|
||||
connect(toolsClient1, SIGNAL(connectedStatusChanged(QmlDebugClient::Status)),
|
||||
SLOT(toolsClientStatusChanged(QmlDebugClient::Status)));
|
||||
|
||||
connect(toolsClient2, SIGNAL(connectedStatusChanged(QmlDebugClient::Status)),
|
||||
SLOT(clientStatusChanged(QmlDebugClient::Status)));
|
||||
connect(toolsClient2, SIGNAL(connectedStatusChanged(QmlDebugClient::Status)),
|
||||
SLOT(toolsClientStatusChanged(QmlDebugClient::Status)));
|
||||
|
||||
updateConnected();
|
||||
}
|
||||
|
||||
void ClientProxy::clientStatusChanged(QmlDebugClient::Status status)
|
||||
{
|
||||
QString serviceName;
|
||||
float version = 0;
|
||||
if (QmlDebugClient *client
|
||||
= qobject_cast<QmlDebugClient*>(sender())) {
|
||||
serviceName = client->name();
|
||||
version = client->serviceVersion();
|
||||
}
|
||||
|
||||
if (m_adapter)
|
||||
m_adapter.data()->logServiceStatusChange(serviceName, version, status);
|
||||
|
||||
updateConnected();
|
||||
}
|
||||
|
||||
QmlDebugClient *ClientProxy::engineDebugClient() const
|
||||
{
|
||||
return m_engineClient;
|
||||
}
|
||||
|
||||
QmlDebugClient *ClientProxy::toolsClient() const
|
||||
{
|
||||
return m_inspectorHelperClient;
|
||||
}
|
||||
|
||||
void ClientProxy::engineClientStatusChanged(
|
||||
QmlDebugClient::Status status)
|
||||
{
|
||||
if (status == QmlDebugClient::Enabled) {
|
||||
m_engineClient = qobject_cast<BaseEngineDebugClient*>(sender());
|
||||
connect(m_engineClient, SIGNAL(newObjects()), this, SLOT(newObjects()));
|
||||
connect(m_engineClient, SIGNAL(result(quint32,QVariant,QByteArray)),
|
||||
SLOT(onResult(quint32,QVariant,QByteArray)));
|
||||
connect(m_engineClient, SIGNAL(valueChanged(int,QByteArray,QVariant)),
|
||||
SLOT(objectWatchTriggered(int,QByteArray,QVariant)));
|
||||
m_adapter.data()->setEngineDebugClient(m_engineClient);
|
||||
updateConnected();
|
||||
}
|
||||
}
|
||||
|
||||
void ClientProxy::toolsClientStatusChanged(
|
||||
QmlDebugClient::Status status)
|
||||
{
|
||||
if (status == QmlDebugClient::Enabled) {
|
||||
m_inspectorHelperClient = qobject_cast<BaseToolsClient*>(sender());
|
||||
connect(m_inspectorHelperClient, SIGNAL(currentObjectsChanged(QList<int>)),
|
||||
SLOT(onCurrentObjectsChanged(QList<int>)));
|
||||
connect(m_inspectorHelperClient, SIGNAL(zoomToolActivated()),
|
||||
SIGNAL(zoomToolActivated()));
|
||||
connect(m_inspectorHelperClient, SIGNAL(selectToolActivated()),
|
||||
SIGNAL(selectToolActivated()));
|
||||
connect(m_inspectorHelperClient, SIGNAL(selectMarqueeToolActivated()),
|
||||
SIGNAL(selectMarqueeToolActivated()));
|
||||
connect(m_inspectorHelperClient, SIGNAL(animationSpeedChanged(qreal)),
|
||||
SIGNAL(animationSpeedChanged(qreal)));
|
||||
connect(m_inspectorHelperClient, SIGNAL(animationPausedChanged(bool)),
|
||||
SIGNAL(animationPausedChanged(bool)));
|
||||
connect(m_inspectorHelperClient, SIGNAL(designModeBehaviorChanged(bool)),
|
||||
SIGNAL(designModeBehaviorChanged(bool)));
|
||||
connect(m_inspectorHelperClient, SIGNAL(showAppOnTopChanged(bool)),
|
||||
SIGNAL(showAppOnTopChanged(bool)));
|
||||
connect(m_inspectorHelperClient, SIGNAL(reloaded()), this,
|
||||
SIGNAL(serverReloaded()));
|
||||
connect(m_inspectorHelperClient, SIGNAL(logActivity(QString,QString)),
|
||||
m_adapter.data(), SLOT(logServiceActivity(QString,QString)));
|
||||
updateConnected();
|
||||
}
|
||||
}
|
||||
|
||||
void ClientProxy::refreshObjectTree()
|
||||
{
|
||||
if (!m_contextQueryId) {
|
||||
m_objectTreeQueryIds.clear();
|
||||
queryEngineContext(m_engines.value(0).debugId());
|
||||
}
|
||||
}
|
||||
|
||||
void ClientProxy::onCurrentObjectsChanged(const QList<int> &debugIds,
|
||||
bool requestIfNeeded)
|
||||
{
|
||||
QList<QmlDebugObjectReference> selectedItems;
|
||||
m_fetchCurrentObjects.clear();
|
||||
m_fetchCurrentObjectsQueryIds.clear();
|
||||
foreach (int debugId, debugIds) {
|
||||
QmlDebugObjectReference ref = objectReferenceForId(debugId);
|
||||
if (ref.debugId() != -1 && !ref.needsMoreData()) {
|
||||
selectedItems << ref;
|
||||
} else if (requestIfNeeded) {
|
||||
m_fetchCurrentObjectsQueryIds
|
||||
<< fetchContextObject(QmlDebugObjectReference(debugId));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
emit selectedItemsChanged(selectedItems);
|
||||
}
|
||||
|
||||
void ClientProxy::onCurrentObjectsFetched(quint32 queryId,
|
||||
const QVariant &result)
|
||||
{
|
||||
m_fetchCurrentObjectsQueryIds.removeOne(queryId);
|
||||
QmlDebugObjectReference obj
|
||||
= qvariant_cast<QmlDebugObjectReference>(result);
|
||||
m_fetchCurrentObjects.push_front(obj);
|
||||
|
||||
if (!getObjectHierarchy(obj))
|
||||
return;
|
||||
|
||||
foreach (const QmlDebugObjectReference &o, m_fetchCurrentObjects)
|
||||
addObjectToTree(o, false);
|
||||
emit selectedItemsChanged(QList<QmlDebugObjectReference>() <<
|
||||
m_fetchCurrentObjects.last());
|
||||
}
|
||||
|
||||
bool ClientProxy::getObjectHierarchy(const QmlDebugObjectReference &obj)
|
||||
{
|
||||
QmlDebugObjectReference parent = objectReferenceForId(obj.parentId());
|
||||
//for root object
|
||||
if (obj.parentId() == -1)
|
||||
return true;
|
||||
|
||||
//for other objects
|
||||
if (parent.debugId() == -1 || parent.needsMoreData()) {
|
||||
m_fetchCurrentObjectsQueryIds
|
||||
<< fetchContextObject(QmlDebugObjectReference(obj.parentId()));
|
||||
} else {
|
||||
return getObjectHierarchy(parent);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ClientProxy::setSelectedItemsByDebugId(const QList<int> &debugIds)
|
||||
{
|
||||
if (!isConnected())
|
||||
return;
|
||||
|
||||
m_inspectorHelperClient->setCurrentObjects(debugIds);
|
||||
}
|
||||
|
||||
void ClientProxy::setSelectedItemsByObjectId(
|
||||
const QList<QmlDebugObjectReference> &objectRefs)
|
||||
{
|
||||
if (isConnected()) {
|
||||
QList<int> debugIds;
|
||||
|
||||
foreach (const QmlDebugObjectReference &ref, objectRefs) {
|
||||
debugIds << ref.debugId();
|
||||
}
|
||||
|
||||
m_inspectorHelperClient->setCurrentObjects(debugIds);
|
||||
}
|
||||
}
|
||||
|
||||
void ClientProxy::addObjectToTree(const QmlDebugObjectReference &obj,
|
||||
bool notify)
|
||||
{
|
||||
int count = m_rootObjects.count();
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (m_rootObjects[i].insertObjectInTree(obj)) {
|
||||
buildDebugIdHashRecursive(obj);
|
||||
if (notify)
|
||||
emit objectTreeUpdated();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QmlDebugObjectReference ClientProxy::objectReferenceForId(int debugId) const
|
||||
{
|
||||
foreach (const QmlDebugObjectReference &it, m_rootObjects) {
|
||||
QmlDebugObjectReference result = objectReferenceForId(debugId, it);
|
||||
if (result.debugId() == debugId)
|
||||
return result;
|
||||
}
|
||||
return QmlDebugObjectReference();
|
||||
}
|
||||
|
||||
void ClientProxy::log(LogDirection direction, const QString &message)
|
||||
{
|
||||
QString msg;
|
||||
if (direction == LogSend) {
|
||||
msg += " sending ";
|
||||
} else {
|
||||
msg += " receiving ";
|
||||
}
|
||||
msg += message;
|
||||
|
||||
if (m_adapter)
|
||||
m_adapter.data()->logServiceActivity("QmlDebug", msg);
|
||||
}
|
||||
|
||||
QList<QmlDebugObjectReference>
|
||||
QmlJSInspector::Internal::ClientProxy::rootObjectReference() const
|
||||
{
|
||||
return m_rootObjects;
|
||||
}
|
||||
|
||||
QmlDebugObjectReference
|
||||
ClientProxy::objectReferenceForId(
|
||||
int debugId,
|
||||
const QmlDebugObjectReference &objectRef) const
|
||||
{
|
||||
if (objectRef.debugId() == debugId)
|
||||
return objectRef;
|
||||
|
||||
foreach (const QmlDebugObjectReference &child, objectRef.children()) {
|
||||
QmlDebugObjectReference result = objectReferenceForId(debugId, child);
|
||||
if (result.debugId() == debugId)
|
||||
return result;
|
||||
}
|
||||
|
||||
return QmlDebugObjectReference();
|
||||
}
|
||||
|
||||
QmlDebugObjectReference ClientProxy::objectReferenceForId(
|
||||
const QString &objectId) const
|
||||
{
|
||||
if (!objectId.isEmpty() && objectId[0].isLower()) {
|
||||
const QList<QmlDebugObjectReference> refs = objectReferences();
|
||||
foreach (const QmlDebugObjectReference &ref, refs) {
|
||||
if (ref.idString() == objectId)
|
||||
return ref;
|
||||
}
|
||||
}
|
||||
return QmlDebugObjectReference();
|
||||
}
|
||||
|
||||
QmlDebugObjectReference ClientProxy::objectReferenceForLocation(
|
||||
int line, int column) const
|
||||
{
|
||||
const QList<QmlDebugObjectReference> refs = objectReferences();
|
||||
foreach (const QmlDebugObjectReference &ref, refs) {
|
||||
if (ref.source().lineNumber() == line
|
||||
&& ref.source().columnNumber() == column)
|
||||
return ref;
|
||||
}
|
||||
|
||||
return QmlDebugObjectReference();
|
||||
}
|
||||
|
||||
QList<QmlDebugObjectReference> ClientProxy::objectReferences() const
|
||||
{
|
||||
QList<QmlDebugObjectReference> result;
|
||||
foreach (const QmlDebugObjectReference &it, m_rootObjects) {
|
||||
result.append(objectReferences(it));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QList<QmlDebugObjectReference>
|
||||
ClientProxy::objectReferences(const QmlDebugObjectReference &objectRef) const
|
||||
{
|
||||
QList<QmlDebugObjectReference> result;
|
||||
result.append(objectRef);
|
||||
|
||||
foreach (const QmlDebugObjectReference &child, objectRef.children()) {
|
||||
result.append(objectReferences(child));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
quint32 ClientProxy::setBindingForObject(int objectDebugId,
|
||||
const QString &propertyName,
|
||||
const QVariant &value,
|
||||
bool isLiteralValue,
|
||||
QString source,
|
||||
int line)
|
||||
{
|
||||
if (objectDebugId == -1)
|
||||
return false;
|
||||
|
||||
if (propertyName == QLatin1String("id"))
|
||||
return false; // Crashes the QMLViewer.
|
||||
|
||||
if (!isConnected())
|
||||
return false;
|
||||
|
||||
log(LogSend, QString("SET_BINDING %1 %2 %3 %4").arg(
|
||||
QString::number(objectDebugId), propertyName, value.toString(),
|
||||
QString(isLiteralValue ? "true" : "false")));
|
||||
|
||||
quint32 queryId = m_engineClient->setBindingForObject(
|
||||
objectDebugId, propertyName, value.toString(), isLiteralValue,
|
||||
source, line);
|
||||
|
||||
if (!queryId)
|
||||
log(LogSend, QString("failed!"));
|
||||
|
||||
return queryId;
|
||||
}
|
||||
|
||||
quint32 ClientProxy::setMethodBodyForObject(int objectDebugId,
|
||||
const QString &methodName,
|
||||
const QString &methodBody)
|
||||
{
|
||||
if (objectDebugId == -1)
|
||||
return false;
|
||||
|
||||
if (!isConnected())
|
||||
return false;
|
||||
|
||||
log(LogSend, QString("SET_METHOD_BODY %1 %2 %3").arg(
|
||||
QString::number(objectDebugId), methodName, methodBody));
|
||||
|
||||
quint32 queryId = m_engineClient->setMethodBody(
|
||||
objectDebugId, methodName, methodBody);
|
||||
|
||||
if (!queryId)
|
||||
log(LogSend, QString("failed!"));
|
||||
|
||||
return queryId;
|
||||
}
|
||||
|
||||
quint32 ClientProxy::resetBindingForObject(int objectDebugId,
|
||||
const QString &propertyName)
|
||||
{
|
||||
if (objectDebugId == -1)
|
||||
return false;
|
||||
|
||||
if (!isConnected())
|
||||
return false;
|
||||
|
||||
log(LogSend, QString("RESET_BINDING %1 %2").arg(
|
||||
QString::number(objectDebugId), propertyName));
|
||||
|
||||
quint32 queryId = m_engineClient->resetBindingForObject(
|
||||
objectDebugId, propertyName);
|
||||
|
||||
if (!queryId)
|
||||
log(LogSend, QString("failed!"));
|
||||
|
||||
return queryId;
|
||||
}
|
||||
|
||||
quint32 ClientProxy::queryExpressionResult(int objectDebugId,
|
||||
const QString &expr)
|
||||
{
|
||||
if (objectDebugId == -1)
|
||||
return 0;
|
||||
|
||||
if (!isConnected())
|
||||
return 0;
|
||||
|
||||
bool block = false;
|
||||
if (m_adapter)
|
||||
block = m_adapter.data()->disableJsDebugging(true);
|
||||
|
||||
log(LogSend, QString("EVAL_EXPRESSION %1 %2").arg(
|
||||
QString::number(objectDebugId), expr));
|
||||
quint32 queryId
|
||||
= m_engineClient->queryExpressionResult(objectDebugId, expr);
|
||||
|
||||
if (m_adapter)
|
||||
m_adapter.data()->disableJsDebugging(block);
|
||||
return queryId;
|
||||
}
|
||||
|
||||
void ClientProxy::clearComponentCache()
|
||||
{
|
||||
if (isConnected())
|
||||
m_inspectorHelperClient->clearComponentCache();
|
||||
}
|
||||
|
||||
bool ClientProxy::addObjectWatch(int objectDebugId)
|
||||
{
|
||||
if (objectDebugId == -1)
|
||||
return false;
|
||||
|
||||
if (!isConnected())
|
||||
return false;
|
||||
|
||||
// already set
|
||||
if (m_objectWatches.contains(objectDebugId))
|
||||
return true;
|
||||
|
||||
QmlDebugObjectReference ref = objectReferenceForId(objectDebugId);
|
||||
if (ref.debugId() != objectDebugId)
|
||||
return false;
|
||||
|
||||
// is flooding the debugging output log!
|
||||
// log(LogSend, QString("WATCH_PROPERTY %1").arg(objectDebugId));
|
||||
|
||||
if (m_engineClient->addWatch(ref))
|
||||
m_objectWatches.append(objectDebugId);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ClientProxy::isObjectBeingWatched(int objectDebugId)
|
||||
{
|
||||
return m_objectWatches.contains(objectDebugId);
|
||||
}
|
||||
|
||||
|
||||
void ClientProxy::objectWatchTriggered(int objectDebugId,
|
||||
const QByteArray &propertyName,
|
||||
const QVariant &propertyValue)
|
||||
{
|
||||
if (m_objectWatches.contains(objectDebugId))
|
||||
emit propertyChanged(objectDebugId, propertyName, propertyValue);
|
||||
}
|
||||
|
||||
bool ClientProxy::removeObjectWatch(int objectDebugId)
|
||||
{
|
||||
if (objectDebugId == -1)
|
||||
return false;
|
||||
|
||||
if (!m_objectWatches.contains(objectDebugId))
|
||||
return false;
|
||||
|
||||
if (!isConnected())
|
||||
return false;
|
||||
|
||||
m_objectWatches.removeOne(objectDebugId);
|
||||
return true;
|
||||
}
|
||||
|
||||
void ClientProxy::removeAllObjectWatches()
|
||||
{
|
||||
foreach (int watchedObject, m_objectWatches)
|
||||
removeObjectWatch(watchedObject);
|
||||
}
|
||||
|
||||
void ClientProxy::queryEngineContext(int id)
|
||||
{
|
||||
if (id < 0)
|
||||
return;
|
||||
|
||||
if (!isConnected())
|
||||
return;
|
||||
|
||||
if (m_contextQueryId)
|
||||
m_contextQueryId = 0;
|
||||
|
||||
log(LogSend, QString("LIST_OBJECTS %1").arg(QString::number(id)));
|
||||
|
||||
m_contextQueryId
|
||||
= m_engineClient->queryRootContexts(QmlDebugEngineReference(id));
|
||||
}
|
||||
|
||||
void ClientProxy::contextChanged(const QVariant &value)
|
||||
{
|
||||
|
||||
if (m_contextQueryId) {
|
||||
m_contextQueryId = 0;
|
||||
emit rootContext(value);
|
||||
}
|
||||
}
|
||||
|
||||
quint32 ClientProxy::fetchContextObject(const QmlDebugObjectReference &obj)
|
||||
{
|
||||
if (!isConnected())
|
||||
return 0;
|
||||
|
||||
log(LogSend, QString("FETCH_OBJECT %1").arg(obj.idString()));
|
||||
return m_engineClient->queryObject(obj);
|
||||
}
|
||||
|
||||
void ClientProxy::fetchRootObjects(
|
||||
const QmlDebugContextReference &context, bool clear)
|
||||
{
|
||||
if (!isConnected())
|
||||
return;
|
||||
if (clear) {
|
||||
m_rootObjects.clear();
|
||||
m_objectTreeQueryIds.clear();
|
||||
}
|
||||
foreach (const QmlDebugObjectReference & obj, context.objects()) {
|
||||
quint32 queryId = 0;
|
||||
using namespace QmlDebug::Constants;
|
||||
if (m_engineClient->objectName() == QML_DEBUGGER &&
|
||||
m_engineClient->serviceVersion() >= CURRENT_SUPPORTED_VERSION) {
|
||||
//Fetch only root objects
|
||||
if (obj.parentId() == -1)
|
||||
queryId = fetchContextObject(obj);
|
||||
} else {
|
||||
queryId = m_engineClient->queryObjectRecursive(obj);
|
||||
}
|
||||
|
||||
if (queryId)
|
||||
m_objectTreeQueryIds << queryId;
|
||||
}
|
||||
foreach (const QmlDebugContextReference &child, context.contexts()) {
|
||||
fetchRootObjects(child, false);
|
||||
}
|
||||
}
|
||||
|
||||
void ClientProxy::insertObjectInTreeIfNeeded(
|
||||
const QmlDebugObjectReference &object)
|
||||
{
|
||||
if (!m_rootObjects.contains(object))
|
||||
return;
|
||||
int count = m_rootObjects.count();
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (m_rootObjects[i].parentId() < 0
|
||||
&& m_rootObjects[i].insertObjectInTree(object)) {
|
||||
m_rootObjects.removeOne(object);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClientProxy::onResult(quint32 queryId, const QVariant &value,
|
||||
const QByteArray &type)
|
||||
{
|
||||
if (type == "FETCH_OBJECT_R") {
|
||||
log(LogReceive, QString("FETCH_OBJECT_R %1").arg(
|
||||
qvariant_cast<QmlDebugObjectReference>(value).idString()));
|
||||
} else {
|
||||
log(LogReceive, QLatin1String(type));
|
||||
}
|
||||
|
||||
if (m_objectTreeQueryIds.contains(queryId))
|
||||
objectTreeFetched(queryId, value);
|
||||
else if (queryId == m_engineQueryId)
|
||||
updateEngineList(value);
|
||||
else if (queryId == m_contextQueryId)
|
||||
contextChanged(value);
|
||||
else if (m_fetchCurrentObjectsQueryIds.contains(queryId))
|
||||
onCurrentObjectsFetched(queryId, value);
|
||||
else
|
||||
emit result(queryId, value);
|
||||
}
|
||||
|
||||
void ClientProxy::objectTreeFetched(quint32 queryId, const QVariant &result)
|
||||
{
|
||||
QmlDebugObjectReference obj
|
||||
= qvariant_cast<QmlDebugObjectReference>(result);
|
||||
m_rootObjects.append(obj);
|
||||
|
||||
m_objectTreeQueryIds.removeOne(queryId);
|
||||
if (m_objectTreeQueryIds.isEmpty()) {
|
||||
int old_count = m_debugIdHash.count();
|
||||
m_debugIdHash.clear();
|
||||
m_debugIdHash.reserve(old_count + 1);
|
||||
foreach (const QmlDebugObjectReference &it, m_rootObjects)
|
||||
buildDebugIdHashRecursive(it);
|
||||
emit objectTreeUpdated();
|
||||
|
||||
if (isConnected()) {
|
||||
if (!m_inspectorHelperClient->currentObjects().isEmpty())
|
||||
onCurrentObjectsChanged(m_inspectorHelperClient->currentObjects(),
|
||||
false);
|
||||
|
||||
m_inspectorHelperClient->setObjectIdList(m_rootObjects);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClientProxy::buildDebugIdHashRecursive(const QmlDebugObjectReference &ref)
|
||||
{
|
||||
QUrl fileUrl = ref.source().url();
|
||||
int lineNum = ref.source().lineNumber();
|
||||
int colNum = ref.source().columnNumber();
|
||||
int rev = 0;
|
||||
|
||||
// handle the case where the url contains the revision number encoded.
|
||||
//(for object created by the debugger)
|
||||
static QRegExp rx("(.*)_(\\d+):(\\d+)$");
|
||||
if (rx.exactMatch(fileUrl.path())) {
|
||||
fileUrl.setPath(rx.cap(1));
|
||||
rev = rx.cap(2).toInt();
|
||||
lineNum += rx.cap(3).toInt() - 1;
|
||||
}
|
||||
|
||||
const QString filePath
|
||||
= InspectorUi::instance()->findFileInProject(fileUrl);
|
||||
|
||||
// append the debug ids in the hash
|
||||
m_debugIdHash[qMakePair<QString, int>(filePath, rev)][qMakePair<int, int>(
|
||||
lineNum, colNum)].append(ref.debugId());
|
||||
|
||||
foreach (const QmlDebugObjectReference &it, ref.children())
|
||||
buildDebugIdHashRecursive(it);
|
||||
}
|
||||
|
||||
|
||||
void ClientProxy::reloadQmlViewer()
|
||||
{
|
||||
if (isConnected())
|
||||
m_inspectorHelperClient->reloadViewer();
|
||||
}
|
||||
|
||||
void ClientProxy::setDesignModeBehavior(bool inDesignMode)
|
||||
{
|
||||
if (isConnected())
|
||||
m_inspectorHelperClient->setDesignModeBehavior(inDesignMode);
|
||||
}
|
||||
|
||||
void ClientProxy::setAnimationSpeed(qreal slowDownFactor)
|
||||
{
|
||||
if (isConnected())
|
||||
m_inspectorHelperClient->setAnimationSpeed(slowDownFactor);
|
||||
}
|
||||
|
||||
void ClientProxy::setAnimationPaused(bool paused)
|
||||
{
|
||||
if (isConnected())
|
||||
m_inspectorHelperClient->setAnimationPaused(paused);
|
||||
}
|
||||
|
||||
void ClientProxy::changeToZoomTool()
|
||||
{
|
||||
if (isConnected())
|
||||
m_inspectorHelperClient->changeToZoomTool();
|
||||
}
|
||||
void ClientProxy::changeToSelectTool()
|
||||
{
|
||||
if (isConnected())
|
||||
m_inspectorHelperClient->changeToSelectTool();
|
||||
}
|
||||
|
||||
void ClientProxy::changeToSelectMarqueeTool()
|
||||
{
|
||||
if (isConnected())
|
||||
m_inspectorHelperClient->changeToSelectMarqueeTool();
|
||||
}
|
||||
|
||||
void ClientProxy::showAppOnTop(bool showOnTop)
|
||||
{
|
||||
if (isConnected())
|
||||
m_inspectorHelperClient->showAppOnTop(showOnTop);
|
||||
}
|
||||
|
||||
void ClientProxy::createQmlObject(const QString &qmlText, int parentDebugId,
|
||||
const QStringList &imports,
|
||||
const QString &filename, int order)
|
||||
{
|
||||
if (isConnected())
|
||||
m_inspectorHelperClient->createQmlObject(qmlText, parentDebugId, imports,
|
||||
filename, order);
|
||||
}
|
||||
|
||||
void ClientProxy::destroyQmlObject(int debugId)
|
||||
{
|
||||
if (isConnected())
|
||||
m_inspectorHelperClient->destroyQmlObject(debugId);
|
||||
}
|
||||
|
||||
void ClientProxy::reparentQmlObject(int debugId, int newParent)
|
||||
{
|
||||
if (isConnected())
|
||||
m_inspectorHelperClient->reparentQmlObject(debugId, newParent);
|
||||
}
|
||||
|
||||
void ClientProxy::updateConnected()
|
||||
{
|
||||
bool isConnected = m_inspectorHelperClient &&
|
||||
m_inspectorHelperClient->status() == QmlDebugClient::Enabled &&
|
||||
m_engineClient &&
|
||||
m_engineClient->status() == QmlDebugClient::Enabled;
|
||||
|
||||
if (isConnected != m_isConnected) {
|
||||
m_isConnected = isConnected;
|
||||
if (isConnected) {
|
||||
emit connected();
|
||||
reloadEngines();
|
||||
} else {
|
||||
emit disconnected();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClientProxy::reloadEngines()
|
||||
{
|
||||
if (!isConnected())
|
||||
return;
|
||||
|
||||
emit aboutToReloadEngines();
|
||||
|
||||
log(LogSend, QString("LIST_ENGINES"));
|
||||
|
||||
m_engineQueryId = m_engineClient->queryAvailableEngines();
|
||||
}
|
||||
|
||||
QList<QmlDebugEngineReference> ClientProxy::engines() const
|
||||
{
|
||||
return m_engines;
|
||||
}
|
||||
|
||||
void ClientProxy::updateEngineList(const QVariant &value)
|
||||
{
|
||||
m_engines = qvariant_cast<QmlDebugEngineReferenceList>(value);
|
||||
m_engineQueryId = 0;
|
||||
emit enginesChanged();
|
||||
}
|
||||
|
||||
Debugger::QmlAdapter *ClientProxy::qmlAdapter() const
|
||||
{
|
||||
return m_adapter.data();
|
||||
}
|
||||
|
||||
bool ClientProxy::isConnected() const
|
||||
{
|
||||
return m_isConnected;
|
||||
}
|
||||
|
||||
void ClientProxy::newObjects()
|
||||
{
|
||||
log(LogReceive, QString("OBJECT_CREATED"));
|
||||
refreshObjectTree();
|
||||
}
|
@@ -1,219 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
#ifndef QMLJSCLIENTPROXY_H
|
||||
#define QMLJSCLIENTPROXY_H
|
||||
|
||||
#include "qmljsinspectorplugin.h"
|
||||
#include <qmldebug/baseenginedebugclient.h>
|
||||
#include <QObject>
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QUrl)
|
||||
|
||||
using namespace QmlDebug;
|
||||
|
||||
namespace Debugger {
|
||||
class QmlAdapter;
|
||||
}
|
||||
|
||||
namespace QmlJSInspector {
|
||||
|
||||
//map <filename, editorRevision> -> <lineNumber, columnNumber> -> debugIds
|
||||
typedef
|
||||
QHash<QPair<QString, int>, QHash<QPair<int, int>, QList<int> > > DebugIdHash;
|
||||
|
||||
namespace Internal {
|
||||
|
||||
class InspectorPlugin;
|
||||
class BaseToolsClient;
|
||||
|
||||
|
||||
class ClientProxy : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ClientProxy(Debugger::QmlAdapter *adapter, QObject *parent = 0);
|
||||
~ClientProxy();
|
||||
|
||||
quint32 setBindingForObject(int objectDebugId,
|
||||
const QString &propertyName,
|
||||
const QVariant &value,
|
||||
bool isLiteralValue,
|
||||
QString source,
|
||||
int line);
|
||||
|
||||
quint32 setMethodBodyForObject(int objectDebugId, const QString &methodName,
|
||||
const QString &methodBody);
|
||||
quint32 resetBindingForObject(int objectDebugId,
|
||||
const QString &propertyName);
|
||||
quint32 queryExpressionResult(int objectDebugId, const QString &expr);
|
||||
void clearComponentCache();
|
||||
|
||||
bool addObjectWatch(int objectDebugId);
|
||||
bool isObjectBeingWatched(int objectDebugId);
|
||||
bool removeObjectWatch(int objectDebugId);
|
||||
void removeAllObjectWatches();
|
||||
|
||||
// returns the object references
|
||||
QList<QmlDebugObjectReference> objectReferences() const;
|
||||
QmlDebugObjectReference objectReferenceForId(int debugId) const;
|
||||
QmlDebugObjectReference objectReferenceForId(const QString &objectId) const;
|
||||
QmlDebugObjectReference objectReferenceForLocation(int line,
|
||||
int column) const;
|
||||
QList<QmlDebugObjectReference> rootObjectReference() const;
|
||||
DebugIdHash debugIdHash() const { return m_debugIdHash; }
|
||||
|
||||
bool isConnected() const;
|
||||
|
||||
void setSelectedItemsByDebugId(const QList<int> &debugIds);
|
||||
void setSelectedItemsByObjectId(
|
||||
const QList<QmlDebugObjectReference> &objectRefs);
|
||||
|
||||
QList<QmlDebugEngineReference> engines() const;
|
||||
|
||||
Debugger::QmlAdapter *qmlAdapter() const;
|
||||
|
||||
quint32 fetchContextObject(const QmlDebugObjectReference& obj);
|
||||
void addObjectToTree(const QmlDebugObjectReference &obj, bool notify = true);
|
||||
void fetchRootObjects(const QmlDebugContextReference &context, bool clear);
|
||||
void insertObjectInTreeIfNeeded(const QmlDebugObjectReference &object);
|
||||
|
||||
QmlDebugClient *engineDebugClient() const;
|
||||
QmlDebugClient *toolsClient() const;
|
||||
|
||||
signals:
|
||||
void objectTreeUpdated();
|
||||
void connectionStatusMessage(const QString &text);
|
||||
|
||||
void aboutToReloadEngines();
|
||||
void enginesChanged();
|
||||
|
||||
void selectedItemsChanged(
|
||||
const QList<QmlDebugObjectReference> &selectedItems);
|
||||
|
||||
void connected();
|
||||
void disconnected();
|
||||
|
||||
void selectToolActivated();
|
||||
void selectMarqueeToolActivated();
|
||||
void zoomToolActivated();
|
||||
void animationSpeedChanged(qreal slowDownFactor);
|
||||
void animationPausedChanged(bool paused);
|
||||
void designModeBehaviorChanged(bool inDesignMode);
|
||||
void showAppOnTopChanged(bool showAppOnTop);
|
||||
void serverReloaded();
|
||||
void propertyChanged(int debugId, const QByteArray &propertyName,
|
||||
const QVariant &propertyValue);
|
||||
|
||||
void result(quint32 queryId, const QVariant &result);
|
||||
void rootContext(const QVariant &context);
|
||||
|
||||
public slots:
|
||||
void refreshObjectTree();
|
||||
void queryEngineContext(int id);
|
||||
void reloadQmlViewer();
|
||||
|
||||
void setDesignModeBehavior(bool inDesignMode);
|
||||
void setAnimationSpeed(qreal slowDownFactor);
|
||||
void setAnimationPaused(bool paused);
|
||||
void changeToZoomTool();
|
||||
void changeToSelectTool();
|
||||
void changeToSelectMarqueeTool();
|
||||
void showAppOnTop(bool showOnTop);
|
||||
void createQmlObject(const QString &qmlText, int parentDebugId,
|
||||
const QStringList &imports,
|
||||
const QString &filename = QString(), int order = 0);
|
||||
void destroyQmlObject(int debugId);
|
||||
void reparentQmlObject(int debugId, int newParent);
|
||||
|
||||
private slots:
|
||||
void connectToServer();
|
||||
void clientStatusChanged(QmlDebugClient::Status status);
|
||||
void engineClientStatusChanged(QmlDebugClient::Status status);
|
||||
void toolsClientStatusChanged(QmlDebugClient::Status status);
|
||||
|
||||
void onCurrentObjectsChanged(const QList<int> &debugIds,
|
||||
bool requestIfNeeded = true);
|
||||
void newObjects();
|
||||
void objectWatchTriggered(int debugId, const QByteArray &propertyName,
|
||||
const QVariant &propertyValue);
|
||||
void onResult(quint32 queryId, const QVariant &value,
|
||||
const QByteArray &type);
|
||||
void onCurrentObjectsFetched(quint32 queryId, const QVariant &result);
|
||||
|
||||
private:
|
||||
void contextChanged(const QVariant &value);
|
||||
void updateEngineList(const QVariant &value);
|
||||
void objectTreeFetched(quint32 queryId, const QVariant &result);
|
||||
void updateConnected();
|
||||
void reloadEngines();
|
||||
bool getObjectHierarchy(const QmlDebugObjectReference &obj);
|
||||
|
||||
QList<QmlDebugObjectReference> objectReferences(
|
||||
const QmlDebugObjectReference &objectRef) const;
|
||||
QmlDebugObjectReference objectReferenceForId(
|
||||
int debugId,
|
||||
const QmlDebugObjectReference &ref) const;
|
||||
|
||||
enum LogDirection {
|
||||
LogSend,
|
||||
LogReceive
|
||||
};
|
||||
void log(LogDirection direction, const QString &message);
|
||||
|
||||
|
||||
private:
|
||||
void buildDebugIdHashRecursive(const QmlDebugObjectReference &ref);
|
||||
|
||||
QWeakPointer<Debugger::QmlAdapter> m_adapter;
|
||||
BaseEngineDebugClient *m_engineClient;
|
||||
BaseToolsClient *m_inspectorHelperClient;
|
||||
|
||||
quint32 m_engineQueryId;
|
||||
quint32 m_contextQueryId;
|
||||
QList<quint32> m_objectTreeQueryIds;
|
||||
QList<quint32> m_fetchCurrentObjectsQueryIds;
|
||||
|
||||
QList<QmlDebugObjectReference> m_rootObjects;
|
||||
QList<QmlDebugObjectReference> m_fetchCurrentObjects;
|
||||
QmlDebugEngineReferenceList m_engines;
|
||||
DebugIdHash m_debugIdHash;
|
||||
|
||||
QList<int> m_objectWatches;
|
||||
|
||||
bool m_isConnected;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSInspector
|
||||
|
||||
#endif // QMLJSCLIENTPROXY_H
|
@@ -1,91 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
#include "qmljscontextcrumblepath.h"
|
||||
|
||||
#include <QMouseEvent>
|
||||
#include <QDebug>
|
||||
|
||||
namespace QmlJSInspector {
|
||||
namespace Internal {
|
||||
|
||||
ContextCrumblePath::ContextCrumblePath(QWidget *parent)
|
||||
: CrumblePath(parent)
|
||||
, m_isEmpty(true)
|
||||
{
|
||||
updateContextPath(QStringList(), QList<int>());
|
||||
}
|
||||
|
||||
void ContextCrumblePath::updateContextPath(const QStringList &path,
|
||||
const QList<int> &debugIds)
|
||||
{
|
||||
Q_ASSERT(path.count() == debugIds.count());
|
||||
|
||||
CrumblePath::clear();
|
||||
|
||||
m_isEmpty = path.isEmpty();
|
||||
if (m_isEmpty) {
|
||||
pushElement(tr("[no context]"), -2);
|
||||
} else {
|
||||
for (int i = 0; i < path.count(); i++)
|
||||
pushElement(path[i], debugIds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void ContextCrumblePath::addChildren(const QStringList &childrenNames,
|
||||
const QList<int> &childrenDebugIds)
|
||||
{
|
||||
Q_ASSERT(childrenNames.count() == childrenDebugIds.count());
|
||||
for (int i = 0; i < childrenNames.count(); i++)
|
||||
addChild(childrenNames[i], childrenDebugIds[i]);
|
||||
|
||||
//Sort them alphabetically
|
||||
if (childrenDebugIds.count())
|
||||
sortChildren();
|
||||
}
|
||||
|
||||
void ContextCrumblePath::clear()
|
||||
{
|
||||
updateContextPath(QStringList(), QList<int>());
|
||||
}
|
||||
|
||||
bool ContextCrumblePath::isEmpty() const
|
||||
{
|
||||
return m_isEmpty;
|
||||
}
|
||||
|
||||
int ContextCrumblePath::debugIdForIndex(int index) const
|
||||
{
|
||||
return CrumblePath::dataForIndex(index).toInt();
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSInspector
|
@@ -1,64 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
#ifndef QMLJSCONTEXTCRUMBLEPATH_H
|
||||
#define QMLJSCONTEXTCRUMBLEPATH_H
|
||||
|
||||
#include <utils/crumblepath.h>
|
||||
#include <QStringList>
|
||||
|
||||
namespace QmlJSInspector {
|
||||
namespace Internal {
|
||||
|
||||
class ContextCrumblePath : public Utils::CrumblePath
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ContextCrumblePath(QWidget *parent = 0);
|
||||
|
||||
bool isEmpty() const;
|
||||
int debugIdForIndex(int index) const;
|
||||
|
||||
public slots:
|
||||
void updateContextPath(const QStringList &path, const QList<int> &debugIds);
|
||||
void addChildren(const QStringList &childrenNames,
|
||||
const QList<int> &childrenDebugIds);
|
||||
void clear();
|
||||
|
||||
private:
|
||||
bool m_isEmpty;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSInspector
|
||||
|
||||
#endif // QMLJSCONTEXTCRUMBLEPATH_H
|
@@ -1,192 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QMLJSINSPECTOR_H
|
||||
#define QMLJSINSPECTOR_H
|
||||
|
||||
#include <coreplugin/editormanager/ieditor.h>
|
||||
#include <utils/fileinprojectfinder.h>
|
||||
|
||||
#include <qmldebug/baseenginedebugclient.h>
|
||||
|
||||
#include <qmljs/qmljsdocument.h>
|
||||
#include <qmljs/parser/qmljsastfwd_p.h>
|
||||
|
||||
#include <debugger/debuggerconstants.h>
|
||||
|
||||
#include <QAction>
|
||||
#include <QObject>
|
||||
|
||||
using namespace QmlDebug;
|
||||
|
||||
namespace ProjectExplorer {
|
||||
class Project;
|
||||
class Environment;
|
||||
}
|
||||
|
||||
namespace TextEditor {
|
||||
class ITextEditor;
|
||||
}
|
||||
|
||||
namespace Core {
|
||||
class IContext;
|
||||
}
|
||||
|
||||
namespace QmlJS {
|
||||
class ModelManagerInterface;
|
||||
}
|
||||
|
||||
namespace QmlJSInspector {
|
||||
namespace Internal {
|
||||
|
||||
class QmlJsInspectorToolBar;
|
||||
class QmlJSPropertyInspector;
|
||||
class ClientProxy;
|
||||
class InspectorSettings;
|
||||
class ContextCrumblePath;
|
||||
class QmlJSLiveTextPreview;
|
||||
|
||||
class InspectorUi : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum DebugMode {
|
||||
StandaloneMode,
|
||||
CppProjectWithQmlEngines,
|
||||
QmlProjectWithCppPlugins
|
||||
};
|
||||
|
||||
InspectorUi(QObject *parent = 0);
|
||||
virtual ~InspectorUi();
|
||||
|
||||
void saveSettings() const;
|
||||
void restoreSettings();
|
||||
|
||||
bool showExperimentalWarning();
|
||||
void setShowExperimentalWarning(bool value);
|
||||
|
||||
static InspectorUi *instance();
|
||||
|
||||
QString findFileInProject(const QUrl &fileUrl) const;
|
||||
|
||||
void setupUi();
|
||||
bool isConnected() const;
|
||||
void connected(ClientProxy *clientProxy);
|
||||
void disconnected();
|
||||
void setDebuggerEngine(QObject *qmlEngine);
|
||||
|
||||
signals:
|
||||
void statusMessage(const QString &text);
|
||||
void livePreviewActivated(bool isActivated);
|
||||
|
||||
public slots:
|
||||
void reloadQmlViewer();
|
||||
void serverReloaded();
|
||||
void setApplyChangesToQmlInspector(bool applyChanges);
|
||||
void onResult(quint32 queryId, const QVariant &result);
|
||||
|
||||
private slots:
|
||||
void enable();
|
||||
void disable();
|
||||
void gotoObjectReferenceDefinition(const QmlDebugObjectReference &obj);
|
||||
void selectItems(const QList<QmlDebugObjectReference> &objectReferences);
|
||||
void selectItems(const QList<int> &objectIds);
|
||||
void changeSelectedItems(const QList<QmlDebugObjectReference> &objects);
|
||||
void changePropertyValue(int debugId,const QString &propertyName,
|
||||
const QString &valueExpression, bool isLiteral);
|
||||
void objectTreeReady();
|
||||
void onRootContext(const QVariant &value);
|
||||
|
||||
void updateEngineList();
|
||||
|
||||
void removePreviewForEditor(Core::IEditor *newEditor);
|
||||
QmlJSLiveTextPreview *createPreviewForEditor(Core::IEditor *newEditor);
|
||||
|
||||
void disableLivePreview();
|
||||
void crumblePathElementClicked(const QVariant &data);
|
||||
|
||||
void updatePendingPreviewDocuments(QmlJS::Document::Ptr doc);
|
||||
void showDebuggerTooltip(const QPoint &mousePos,
|
||||
TextEditor::ITextEditor *editor, int cursorPos);
|
||||
void onEngineStateChanged(Debugger::DebuggerState state);
|
||||
|
||||
private:
|
||||
void showRoot();
|
||||
void resetViews();
|
||||
|
||||
void initializeDocuments();
|
||||
void applyChangesToQmlInspectorHelper(bool applyChanges);
|
||||
void setupDockWidgets();
|
||||
QString filenameForShadowBuildFile(const QString &filename) const;
|
||||
void populateCrumblePath(const QmlDebugObjectReference &objRef);
|
||||
bool isRoot(const QmlDebugObjectReference &obj) const;
|
||||
QmlDebugObjectReference objectReferenceForLocation(
|
||||
const QString &fileName, int cursorPosition = -1) const;
|
||||
|
||||
void connectSignals();
|
||||
void disconnectSignals();
|
||||
|
||||
void showObject(const QmlDebugObjectReference &obj);
|
||||
|
||||
QmlDebugObjectReference findParentRecursive(
|
||||
int goalDebugId,
|
||||
const QList<QmlDebugObjectReference > &objectsToSearch);
|
||||
private:
|
||||
bool m_listeningToEditorManager;
|
||||
QmlJsInspectorToolBar *m_toolBar;
|
||||
ContextCrumblePath *m_crumblePath;
|
||||
QmlJSPropertyInspector *m_propertyInspector;
|
||||
|
||||
InspectorSettings *m_settings;
|
||||
ClientProxy *m_clientProxy;
|
||||
quint32 m_debugQuery;
|
||||
quint32 m_showObjectQueryId;
|
||||
QList<quint32> m_updateObjectQueryIds;
|
||||
|
||||
// Qml/JS integration
|
||||
QHash<QString, QmlJSLiveTextPreview *> m_textPreviews;
|
||||
QmlJS::Snapshot m_loadedSnapshot; //the snapshot loaded by the viewer
|
||||
|
||||
QStringList m_pendingPreviewDocumentNames;
|
||||
Utils::FileInProjectFinder m_projectFinder;
|
||||
|
||||
static InspectorUi *m_instance;
|
||||
bool m_selectionCallbackExpected;
|
||||
bool m_cursorPositionChangedExternally;
|
||||
bool m_onCrumblePathClicked;
|
||||
};
|
||||
|
||||
} // Internal
|
||||
} // QmlJSInspector
|
||||
|
||||
#endif // QMLJSINSPECTOR_H
|
@@ -1,51 +0,0 @@
|
||||
TEMPLATE = lib
|
||||
TARGET = QmlJSInspector
|
||||
INCLUDEPATH += .
|
||||
DEPENDPATH += .
|
||||
QT += network
|
||||
greaterThan(QT_MAJOR_VERSION, 4) {
|
||||
QT += quick1
|
||||
} else {
|
||||
QT += declarative
|
||||
}
|
||||
|
||||
DEFINES += QMLJSINSPECTOR_LIBRARY
|
||||
|
||||
HEADERS += \
|
||||
qmljsinspector_global.h \
|
||||
qmljsinspectorconstants.h \
|
||||
qmljsinspectorplugin.h \
|
||||
qmljsclientproxy.h \
|
||||
qmljsinspector.h \
|
||||
qmljsinspectortoolbar.h \
|
||||
qmljslivetextpreview.h \
|
||||
basetoolsclient.h \
|
||||
qmljscontextcrumblepath.h \
|
||||
qmljsinspectorsettings.h \
|
||||
qmljspropertyinspector.h \
|
||||
declarativetoolsclient.h \
|
||||
qmltoolsclient.h
|
||||
|
||||
SOURCES += \
|
||||
qmljsinspectorplugin.cpp \
|
||||
qmljsclientproxy.cpp \
|
||||
qmljsinspector.cpp \
|
||||
qmljsinspectortoolbar.cpp \
|
||||
qmljslivetextpreview.cpp \
|
||||
basetoolsclient.cpp \
|
||||
qmljscontextcrumblepath.cpp \
|
||||
qmljsinspectorsettings.cpp \
|
||||
qmljspropertyinspector.cpp \
|
||||
declarativetoolsclient.cpp \
|
||||
qmltoolsclient.cpp
|
||||
|
||||
include(../../../share/qtcreator/qml/qmljsdebugger/protocol/protocol.pri)
|
||||
|
||||
RESOURCES += qmljsinspector.qrc
|
||||
|
||||
include(../../qtcreatorplugin.pri)
|
||||
include(../../libs/qmldebug/qmldebug.pri)
|
||||
include(../../libs/qmleditorwidgets/qmleditorwidgets.pri)
|
||||
|
||||
include(../../plugins/debugger/debugger.pri)
|
||||
include(../../plugins/qmljstools/qmljstools.pri)
|
@@ -1,59 +0,0 @@
|
||||
import qbs.base 1.0
|
||||
|
||||
import "../QtcPlugin.qbs" as QtcPlugin
|
||||
|
||||
QtcPlugin {
|
||||
name: "QmlJSInspector"
|
||||
|
||||
Depends { name: "qt"; submodules: ['widgets', 'quick1'] }
|
||||
Depends { name: "Core" }
|
||||
Depends { name: "Debugger" }
|
||||
Depends { name: "LanguageUtils" }
|
||||
Depends { name: "TextEditor" }
|
||||
Depends { name: "QmlJS" }
|
||||
Depends { name: "QmlJSTools" }
|
||||
Depends { name: "QmlEditorWidgets" }
|
||||
Depends { name: "QmlDebug" }
|
||||
|
||||
|
||||
Depends { name: "cpp" }
|
||||
cpp.includePaths: [
|
||||
".",
|
||||
"../../libs/qmleditorwidgets",
|
||||
"../../../share/qtcreator/qml/qmljsdebugger/protocol",
|
||||
"../../shared/symbianutils",
|
||||
"..",
|
||||
"../../libs",
|
||||
buildDirectory
|
||||
]
|
||||
|
||||
files: [
|
||||
"basetoolsclient.h",
|
||||
"declarativetoolsclient.h",
|
||||
"qmljsinspector_global.h",
|
||||
"qmljsinspectorconstants.h",
|
||||
"qmljsinspectorplugin.h",
|
||||
"qmljsclientproxy.h",
|
||||
"qmljsinspector.h",
|
||||
"qmljsinspectortoolbar.h",
|
||||
"qmljslivetextpreview.h",
|
||||
"qmltoolsclient.h",
|
||||
"qmljscontextcrumblepath.h",
|
||||
"qmljsinspectorsettings.h",
|
||||
"qmljspropertyinspector.h",
|
||||
"../../../share/qtcreator/qml/qmljsdebugger/protocol/inspectorprotocol.h",
|
||||
"basetoolsclient.cpp",
|
||||
"declarativetoolsclient.cpp",
|
||||
"qmljsinspectorplugin.cpp",
|
||||
"qmljsclientproxy.cpp",
|
||||
"qmljsinspector.cpp",
|
||||
"qmljsinspectortoolbar.cpp",
|
||||
"qmljslivetextpreview.cpp",
|
||||
"qmltoolsclient.cpp",
|
||||
"qmljscontextcrumblepath.cpp",
|
||||
"qmljsinspectorsettings.cpp",
|
||||
"qmljspropertyinspector.cpp",
|
||||
"qmljsinspector.qrc",
|
||||
]
|
||||
}
|
||||
|
@@ -1,20 +0,0 @@
|
||||
<RCC>
|
||||
<qresource prefix="/qml">
|
||||
<file>images/from-qml.png</file>
|
||||
<file>images/pause.png</file>
|
||||
<file>images/reload.png</file>
|
||||
<file>images/play.png</file>
|
||||
<file>images/select.png</file>
|
||||
<file>images/to-qml.png</file>
|
||||
<file>images/select-marquee.png</file>
|
||||
<file>images/zoom.png</file>
|
||||
<file>images/select-small.png</file>
|
||||
<file>images/play-small.png</file>
|
||||
<file>images/to-qml-small.png</file>
|
||||
<file>images/pause-small.png</file>
|
||||
<file>images/from-qml-small.png</file>
|
||||
<file>images/zoom-small.png</file>
|
||||
<file>images/select-marquee-small.png</file>
|
||||
<file>images/app-on-top.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
@@ -1,43 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
#ifndef QMLINSPECTOR_GLOBAL_H
|
||||
#define QMLINSPECTOR_GLOBAL_H
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#if defined(QMLJSINSPECTOR_LIBRARY)
|
||||
# define QMLINSPECTOR_EXPORT Q_DECL_EXPORT
|
||||
#else
|
||||
# define QMLINSPECTOR_EXPORT Q_DECL_IMPORT
|
||||
#endif
|
||||
|
||||
#endif // QMLINSPECTOR_GLOBAL_H
|
@@ -1,69 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QMLJSINSPECTORCONSTANTS_H
|
||||
#define QMLJSINSPECTORCONSTANTS_H
|
||||
|
||||
namespace QmlJSInspector {
|
||||
namespace Constants {
|
||||
|
||||
const char INFO_EXPERIMENTAL[] = "QmlInspector.Experimental";
|
||||
const char INFO_OUT_OF_SYNC[] = "QmlInspector.OutOfSyncWarning";
|
||||
|
||||
const char PLAY_ACTION[] = "QmlInspector.Play";
|
||||
const char SELECT_ACTION[] = "QmlInspector.Select";
|
||||
const char ZOOM_ACTION[] = "QmlInspector.Zoom";
|
||||
const char FROM_QML_ACTION[] = "QmlInspector.FromQml";
|
||||
const char SHOW_APP_ON_TOP_ACTION[] = "QmlInspector.ShowAppOnTop";
|
||||
|
||||
// Settings
|
||||
const char S_QML_INSPECTOR [] = "QML.Inspector";
|
||||
const char S_LIVE_PREVIEW_WARNING_KEY[] = "ShowLivePreview";
|
||||
|
||||
const char ALWAYS_ADJUST_COLUMNS_WIDTHS[] = "AlwaysAdjustColumnWidths";
|
||||
|
||||
const char QML_INSPECTOR[] = "QmlInspector";
|
||||
const char QDECLARATIVE_OBSERVER_MODE[] = "QDeclarativeObserverMode";
|
||||
|
||||
enum DesignTool {
|
||||
NoTool = 0,
|
||||
SelectionToolMode = 1,
|
||||
MarqueeSelectionToolMode = 2,
|
||||
MoveToolMode = 3,
|
||||
ResizeToolMode = 4,
|
||||
ZoomMode = 6
|
||||
};
|
||||
|
||||
} // namespace Constants
|
||||
} // namespace QmlJSInspector
|
||||
|
||||
#endif // QMLJSINSPECTORCONSTANTS_H
|
@@ -1,153 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "qmljsinspectorplugin.h"
|
||||
|
||||
#include "qmljsclientproxy.h"
|
||||
#include "qmljsinspector.h"
|
||||
#include "qmljsinspectorconstants.h"
|
||||
#include "qmljsinspectortoolbar.h"
|
||||
|
||||
#include <coreplugin/coreconstants.h>
|
||||
#include <coreplugin/icontext.h>
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/imode.h>
|
||||
#include <coreplugin/modemanager.h>
|
||||
#include <debugger/debuggerconstants.h>
|
||||
#include <debugger/qml/qmladapter.h>
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QStringList>
|
||||
#include <QtPlugin>
|
||||
#include <QTimer>
|
||||
|
||||
#include <QHBoxLayout>
|
||||
#include <QToolButton>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
using namespace QmlJSInspector::Internal;
|
||||
using namespace QmlJSInspector::Constants;
|
||||
|
||||
InspectorPlugin::InspectorPlugin()
|
||||
: IPlugin()
|
||||
, m_clientProxy(0)
|
||||
{
|
||||
m_inspectorUi = new InspectorUi(this);
|
||||
}
|
||||
|
||||
InspectorPlugin::~InspectorPlugin()
|
||||
{
|
||||
}
|
||||
|
||||
InspectorUi *InspectorPlugin::inspector() const
|
||||
{
|
||||
return m_inspectorUi;
|
||||
}
|
||||
|
||||
ExtensionSystem::IPlugin::ShutdownFlag InspectorPlugin::aboutToShutdown()
|
||||
{
|
||||
m_inspectorUi->saveSettings();
|
||||
return SynchronousShutdown;
|
||||
}
|
||||
|
||||
bool InspectorPlugin::initialize(const QStringList &arguments,
|
||||
QString *errorString)
|
||||
{
|
||||
Q_UNUSED(arguments);
|
||||
Q_UNUSED(errorString);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void InspectorPlugin::extensionsInitialized()
|
||||
{
|
||||
ExtensionSystem::PluginManager *pluginManager
|
||||
= ExtensionSystem::PluginManager::instance();
|
||||
|
||||
connect(pluginManager, SIGNAL(objectAdded(QObject*)),
|
||||
SLOT(objectAdded(QObject*)));
|
||||
connect(Core::ModeManager::instance(),
|
||||
SIGNAL(currentModeAboutToChange(Core::IMode*)),
|
||||
this, SLOT(modeAboutToChange(Core::IMode*)));
|
||||
}
|
||||
|
||||
void InspectorPlugin::objectAdded(QObject *object)
|
||||
{
|
||||
Debugger::QmlAdapter *adapter = qobject_cast<Debugger::QmlAdapter *>(object);
|
||||
if (adapter) {
|
||||
//Disconnect inspector plugin when qml adapter emits disconnected
|
||||
connect(adapter, SIGNAL(disconnected()), this, SLOT(disconnect()));
|
||||
m_clientProxy = new ClientProxy(adapter);
|
||||
if (m_clientProxy->isConnected()) {
|
||||
clientProxyConnected();
|
||||
} else {
|
||||
connect(m_clientProxy, SIGNAL(connected()),
|
||||
this, SLOT(clientProxyConnected()));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (object->objectName() == QLatin1String("QmlEngine"))
|
||||
m_inspectorUi->setDebuggerEngine(object);
|
||||
}
|
||||
|
||||
void InspectorPlugin::disconnect()
|
||||
{
|
||||
if (m_inspectorUi->isConnected()) {
|
||||
m_inspectorUi->disconnected();
|
||||
delete m_clientProxy;
|
||||
m_clientProxy = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void InspectorPlugin::clientProxyConnected()
|
||||
{
|
||||
m_inspectorUi->connected(m_clientProxy);
|
||||
}
|
||||
|
||||
void InspectorPlugin::modeAboutToChange(Core::IMode *newMode)
|
||||
{
|
||||
QTC_ASSERT(newMode, return);
|
||||
|
||||
if (newMode->id() == Debugger::Constants::MODE_DEBUG) {
|
||||
m_inspectorUi->setupUi();
|
||||
|
||||
// Make sure we're not called again.
|
||||
QObject::disconnect(Core::ModeManager::instance(),
|
||||
SIGNAL(currentModeAboutToChange(Core::IMode*)),
|
||||
this, SLOT(modeAboutToChange(Core::IMode*)));
|
||||
}
|
||||
}
|
||||
|
||||
Q_EXPORT_PLUGIN(InspectorPlugin)
|
@@ -1,88 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
#ifndef QMLJSINSPECTORPLUGIN_H
|
||||
#define QMLJSINSPECTORPLUGIN_H
|
||||
|
||||
#include <extensionsystem/iplugin.h>
|
||||
#include <qmljs/qmljsmodelmanagerinterface.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
#include <QTimer>
|
||||
|
||||
namespace Core {
|
||||
class IMode;
|
||||
} // namespace Core
|
||||
|
||||
namespace QmlJSInspector {
|
||||
namespace Internal {
|
||||
|
||||
class ClientProxy;
|
||||
class InspectorUi;
|
||||
|
||||
class InspectorPlugin : public ExtensionSystem::IPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin"
|
||||
FILE "QmlJSInspector.json")
|
||||
|
||||
public:
|
||||
InspectorPlugin();
|
||||
virtual ~InspectorPlugin();
|
||||
|
||||
//static InspectorPlugin *instance();
|
||||
|
||||
InspectorUi *inspector() const;
|
||||
|
||||
// ExtensionSystem::IPlugin interface
|
||||
virtual bool initialize(const QStringList &arguments, QString *errorString);
|
||||
virtual void extensionsInitialized();
|
||||
virtual ExtensionSystem::IPlugin::ShutdownFlag aboutToShutdown();
|
||||
|
||||
private slots:
|
||||
void objectAdded(QObject *object);
|
||||
void disconnect();
|
||||
void clientProxyConnected();
|
||||
void modeAboutToChange(Core::IMode *mode);
|
||||
|
||||
private:
|
||||
void createActions();
|
||||
|
||||
private:
|
||||
ClientProxy *m_clientProxy;
|
||||
InspectorUi *m_inspectorUi;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSInspector
|
||||
|
||||
#endif // QMLINSPECTORPLUGIN_H
|
@@ -1,76 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "qmljsinspectorsettings.h"
|
||||
#include "qmljsinspectorconstants.h"
|
||||
#include <QSettings>
|
||||
|
||||
namespace QmlJSInspector {
|
||||
namespace Internal {
|
||||
|
||||
using namespace QmlJSInspector::Constants;
|
||||
|
||||
InspectorSettings::InspectorSettings(QObject *parent)
|
||||
: QObject(parent),
|
||||
m_showLivePreviewWarning(true)
|
||||
{
|
||||
}
|
||||
|
||||
void InspectorSettings::restoreSettings(QSettings *settings)
|
||||
{
|
||||
settings->beginGroup(QLatin1String(S_QML_INSPECTOR));
|
||||
m_showLivePreviewWarning
|
||||
= settings->value(QLatin1String(S_LIVE_PREVIEW_WARNING_KEY),
|
||||
true).toBool();
|
||||
settings->endGroup();
|
||||
}
|
||||
|
||||
void InspectorSettings::saveSettings(QSettings *settings) const
|
||||
{
|
||||
settings->beginGroup(QLatin1String(S_QML_INSPECTOR));
|
||||
settings->setValue(QLatin1String(S_LIVE_PREVIEW_WARNING_KEY),
|
||||
m_showLivePreviewWarning);
|
||||
settings->endGroup();
|
||||
}
|
||||
|
||||
bool InspectorSettings::showLivePreviewWarning() const
|
||||
{
|
||||
return m_showLivePreviewWarning;
|
||||
}
|
||||
|
||||
void InspectorSettings::setShowLivePreviewWarning(bool value)
|
||||
{
|
||||
m_showLivePreviewWarning = value;
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSInspector
|
@@ -1,63 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef INSPECTORSETTINGS_H
|
||||
#define INSPECTORSETTINGS_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QSettings)
|
||||
|
||||
namespace QmlJSInspector {
|
||||
namespace Internal {
|
||||
|
||||
class InspectorSettings : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
InspectorSettings(QObject *parent = 0);
|
||||
|
||||
void restoreSettings(QSettings *settings);
|
||||
void saveSettings(QSettings *settings) const;
|
||||
|
||||
bool showLivePreviewWarning() const;
|
||||
void setShowLivePreviewWarning(bool value);
|
||||
|
||||
private:
|
||||
bool m_showLivePreviewWarning;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSInspector
|
||||
|
||||
#endif // INSPECTORSETTINGS_H
|
@@ -1,373 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#include "qmljsinspectortoolbar.h"
|
||||
|
||||
#include "qmljsinspectorconstants.h"
|
||||
|
||||
#include <coreplugin/actionmanager/actionmanager.h>
|
||||
#include <coreplugin/actionmanager/command.h>
|
||||
#include <coreplugin/id.h>
|
||||
#include <coreplugin/icore.h>
|
||||
#include <debugger/debuggerconstants.h>
|
||||
#include <debugger/debuggermainwindow.h>
|
||||
#include <debugger/debuggerplugin.h>
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
#include <projectexplorer/projectexplorerconstants.h>
|
||||
|
||||
#include <utils/styledbar.h>
|
||||
#include <utils/savedaction.h>
|
||||
|
||||
#include <QAction>
|
||||
#include <QActionGroup>
|
||||
#include <QHBoxLayout>
|
||||
#include <QMenu>
|
||||
#include <QToolButton>
|
||||
#include <QLineEdit>
|
||||
|
||||
namespace QmlJSInspector {
|
||||
namespace Internal {
|
||||
|
||||
static QToolButton *toolButton(QAction *action)
|
||||
{
|
||||
QToolButton *button = new QToolButton;
|
||||
button->setDefaultAction(action);
|
||||
return button;
|
||||
}
|
||||
|
||||
QmlJsInspectorToolBar::QmlJsInspectorToolBar(QObject *parent) :
|
||||
QObject(parent),
|
||||
m_fromQmlAction(0),
|
||||
m_playAction(0),
|
||||
m_selectAction(0),
|
||||
m_zoomAction(0),
|
||||
m_showAppOnTopAction(0),
|
||||
m_playSpeedMenuActions(0),
|
||||
m_playIcon(QIcon(QLatin1String(":/qml/images/play-small.png"))),
|
||||
m_pauseIcon(QIcon(QLatin1String(":/qml/images/pause-small.png"))),
|
||||
m_emitSignals(true),
|
||||
m_paused(false),
|
||||
m_animationSpeed(1.0f),
|
||||
m_designModeActive(false),
|
||||
m_activeTool(NoTool),
|
||||
m_barWidget(0),
|
||||
m_zoomActionEnable(true)
|
||||
{
|
||||
}
|
||||
|
||||
void QmlJsInspectorToolBar::setEnabled(bool value)
|
||||
{
|
||||
m_fromQmlAction->setEnabled(value);
|
||||
m_showAppOnTopAction->setEnabled(value);
|
||||
m_playAction->setEnabled(value);
|
||||
m_selectAction->setEnabled(value);
|
||||
m_zoomAction->setEnabled(value && m_zoomActionEnable);
|
||||
}
|
||||
|
||||
void QmlJsInspectorToolBar::enable()
|
||||
{
|
||||
setEnabled(true);
|
||||
m_emitSignals = false;
|
||||
setAnimationSpeed(1.0f);
|
||||
m_designModeActive = false;
|
||||
updateDesignModeActions(NoTool);
|
||||
m_emitSignals = true;
|
||||
}
|
||||
|
||||
void QmlJsInspectorToolBar::disable()
|
||||
{
|
||||
setAnimationSpeed(1.0f);
|
||||
m_designModeActive = false;
|
||||
updateDesignModeActions(NoTool);
|
||||
setEnabled(false);
|
||||
}
|
||||
|
||||
void QmlJsInspectorToolBar::activateSelectTool()
|
||||
{
|
||||
updateDesignModeActions(SelectionToolMode);
|
||||
}
|
||||
|
||||
void QmlJsInspectorToolBar::activateZoomTool()
|
||||
{
|
||||
updateDesignModeActions(ZoomMode);
|
||||
}
|
||||
|
||||
void QmlJsInspectorToolBar::setAnimationSpeed(qreal slowDownFactor)
|
||||
{
|
||||
if (m_animationSpeed == slowDownFactor)
|
||||
return;
|
||||
|
||||
m_emitSignals = false;
|
||||
m_animationSpeed = slowDownFactor;
|
||||
|
||||
foreach (QAction *action, m_playSpeedMenuActions->actions()) {
|
||||
if (action->data().toReal() == slowDownFactor) {
|
||||
action->setChecked(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_emitSignals = true;
|
||||
}
|
||||
|
||||
void QmlJsInspectorToolBar::setAnimationPaused(bool paused)
|
||||
{
|
||||
if (m_paused == paused)
|
||||
return;
|
||||
|
||||
m_paused = paused;
|
||||
updatePlayAction();
|
||||
}
|
||||
|
||||
void QmlJsInspectorToolBar::setDesignModeBehavior(bool inDesignMode)
|
||||
{
|
||||
m_emitSignals = false;
|
||||
m_designModeActive = inDesignMode;
|
||||
updateDesignModeActions(m_activeTool);
|
||||
m_emitSignals = true;
|
||||
}
|
||||
|
||||
void QmlJsInspectorToolBar::setShowAppOnTop(bool showAppOnTop)
|
||||
{
|
||||
m_emitSignals = false;
|
||||
m_showAppOnTopAction->setChecked(showAppOnTop);
|
||||
m_emitSignals = true;
|
||||
}
|
||||
|
||||
void QmlJsInspectorToolBar::setZoomToolEnabled(bool enable)
|
||||
{
|
||||
m_zoomActionEnable = enable;
|
||||
m_zoomAction->setEnabled(m_zoomActionEnable);
|
||||
}
|
||||
|
||||
void QmlJsInspectorToolBar::createActions()
|
||||
{
|
||||
using namespace Constants;
|
||||
|
||||
Core::Context context(Debugger::Constants::C_QMLDEBUGGER);
|
||||
Core::ActionManager *am = Core::ICore::actionManager();
|
||||
|
||||
m_fromQmlAction = new Utils::SavedAction(this);
|
||||
m_fromQmlAction->setDefaultValue(false);
|
||||
m_fromQmlAction->setSettingsKey(QLatin1String(S_QML_INSPECTOR),
|
||||
QLatin1String(FROM_QML_ACTION));
|
||||
m_fromQmlAction->setText(tr("Apply Changes on Save"));
|
||||
m_fromQmlAction->setCheckable(true);
|
||||
m_fromQmlAction->setIcon(QIcon(QLatin1String(":/qml/images/from-qml-small.png")));
|
||||
|
||||
m_showAppOnTopAction = new Utils::SavedAction(this);
|
||||
m_showAppOnTopAction->setDefaultValue(false);
|
||||
m_showAppOnTopAction->setSettingsKey(QLatin1String(S_QML_INSPECTOR),
|
||||
QLatin1String(SHOW_APP_ON_TOP_ACTION));
|
||||
m_showAppOnTopAction->setText(tr("Show application on top"));
|
||||
m_showAppOnTopAction->setCheckable(true);
|
||||
m_showAppOnTopAction->setIcon(QIcon(QLatin1String(":/qml/images/app-on-top.png")));
|
||||
|
||||
m_playAction =
|
||||
new QAction(m_pauseIcon, tr("Play/Pause Animations"), this);
|
||||
m_selectAction =
|
||||
new QAction(QIcon(QLatin1String(":/qml/images/select-small.png")),
|
||||
tr("Select"), this);
|
||||
m_zoomAction =
|
||||
new QAction(QIcon(QLatin1String(":/qml/images/zoom-small.png")),
|
||||
tr("Zoom"), this);
|
||||
|
||||
m_selectAction->setCheckable(true);
|
||||
m_zoomAction->setCheckable(true);
|
||||
|
||||
Core::Command *command
|
||||
= am->registerAction(m_playAction, PLAY_ACTION, context);
|
||||
command->setAttribute(Core::Command::CA_UpdateIcon);
|
||||
am->registerAction(m_selectAction, SELECT_ACTION, context);
|
||||
am->registerAction(m_zoomAction, ZOOM_ACTION, context);
|
||||
am->registerAction(m_fromQmlAction, FROM_QML_ACTION, context);
|
||||
am->registerAction(m_showAppOnTopAction, SHOW_APP_ON_TOP_ACTION, context);
|
||||
|
||||
m_barWidget = new QWidget;
|
||||
|
||||
QMenu *playSpeedMenu = new QMenu(m_barWidget);
|
||||
m_playSpeedMenuActions = new QActionGroup(this);
|
||||
m_playSpeedMenuActions->setExclusive(true);
|
||||
QAction *speedAction = playSpeedMenu->addAction(tr("1x"),
|
||||
this, SLOT(changeAnimationSpeed()));
|
||||
speedAction->setCheckable(true);
|
||||
speedAction->setChecked(true);
|
||||
speedAction->setData(1.0f);
|
||||
m_playSpeedMenuActions->addAction(speedAction);
|
||||
|
||||
speedAction = playSpeedMenu->addAction(tr("0.5x"),
|
||||
this, SLOT(changeAnimationSpeed()));
|
||||
speedAction->setCheckable(true);
|
||||
speedAction->setData(2.0f);
|
||||
m_playSpeedMenuActions->addAction(speedAction);
|
||||
|
||||
speedAction = playSpeedMenu->addAction(tr("0.25x"),
|
||||
this, SLOT(changeAnimationSpeed()));
|
||||
speedAction->setCheckable(true);
|
||||
speedAction->setData(4.0f);
|
||||
m_playSpeedMenuActions->addAction(speedAction);
|
||||
|
||||
speedAction = playSpeedMenu->addAction(tr("0.125x"),
|
||||
this, SLOT(changeAnimationSpeed()));
|
||||
speedAction->setCheckable(true);
|
||||
speedAction->setData(8.0f);
|
||||
m_playSpeedMenuActions->addAction(speedAction);
|
||||
|
||||
speedAction = playSpeedMenu->addAction(tr("0.1x"),
|
||||
this, SLOT(changeAnimationSpeed()));
|
||||
speedAction->setCheckable(true);
|
||||
speedAction->setData(10.0f);
|
||||
m_playSpeedMenuActions->addAction(speedAction);
|
||||
|
||||
QHBoxLayout *toolBarLayout = new QHBoxLayout(m_barWidget);
|
||||
toolBarLayout->setMargin(0);
|
||||
toolBarLayout->setSpacing(0);
|
||||
|
||||
// QML Helpers
|
||||
toolBarLayout->addWidget(toolButton(am->command(FROM_QML_ACTION)->action()));
|
||||
toolBarLayout->addWidget(
|
||||
toolButton(am->command(SHOW_APP_ON_TOP_ACTION)->action()));
|
||||
m_playButton = toolButton(am->command(PLAY_ACTION)->action());
|
||||
m_playButton->setMenu(playSpeedMenu);
|
||||
toolBarLayout->addWidget(m_playButton);
|
||||
|
||||
// Inspector
|
||||
toolBarLayout->addWidget(new Utils::StyledSeparator);
|
||||
toolBarLayout->addWidget(toolButton(am->command(SELECT_ACTION)->action()));
|
||||
toolBarLayout->addWidget(toolButton(am->command(ZOOM_ACTION)->action()));
|
||||
toolBarLayout->addWidget(new Utils::StyledSeparator);
|
||||
|
||||
connect(m_fromQmlAction, SIGNAL(triggered()),
|
||||
SLOT(activateFromQml()));
|
||||
connect(m_showAppOnTopAction, SIGNAL(triggered()),
|
||||
SLOT(showAppOnTopClick()));
|
||||
connect(m_playAction, SIGNAL(triggered()),
|
||||
SLOT(activatePlayOnClick()));
|
||||
connect(m_selectAction, SIGNAL(triggered(bool)),
|
||||
SLOT(selectToolTriggered(bool)));
|
||||
connect(m_zoomAction, SIGNAL(triggered(bool)),
|
||||
SLOT(zoomToolTriggered(bool)));
|
||||
|
||||
readSettings();
|
||||
connect(Core::ICore::instance(),
|
||||
SIGNAL(saveSettingsRequested()), SLOT(writeSettings()));
|
||||
}
|
||||
|
||||
void QmlJsInspectorToolBar::readSettings()
|
||||
{
|
||||
QSettings *settings = Core::ICore::settings();
|
||||
m_fromQmlAction->readSettings(settings);
|
||||
m_showAppOnTopAction->readSettings(settings);
|
||||
}
|
||||
|
||||
void QmlJsInspectorToolBar::writeSettings() const
|
||||
{
|
||||
QSettings *settings = Core::ICore::settings();
|
||||
m_fromQmlAction->writeSettings(settings);
|
||||
m_showAppOnTopAction->writeSettings(settings);
|
||||
}
|
||||
|
||||
QWidget *QmlJsInspectorToolBar::widget() const
|
||||
{
|
||||
return m_barWidget;
|
||||
}
|
||||
|
||||
void QmlJsInspectorToolBar::changeAnimationSpeed()
|
||||
{
|
||||
QAction *action = static_cast<QAction*>(sender());
|
||||
|
||||
m_animationSpeed = action->data().toReal();
|
||||
emit animationSpeedChanged(m_animationSpeed);
|
||||
|
||||
updatePlayAction();
|
||||
}
|
||||
|
||||
void QmlJsInspectorToolBar::activatePlayOnClick()
|
||||
{
|
||||
m_paused = !m_paused;
|
||||
emit animationPausedChanged(m_paused);
|
||||
updatePlayAction();
|
||||
}
|
||||
|
||||
void QmlJsInspectorToolBar::updatePlayAction()
|
||||
{
|
||||
m_playAction->setIcon(m_paused ? m_playIcon : m_pauseIcon);
|
||||
}
|
||||
|
||||
void QmlJsInspectorToolBar::selectToolTriggered(bool checked)
|
||||
{
|
||||
if (m_designModeActive != checked) {
|
||||
m_designModeActive = checked;
|
||||
emit designModeSelected(checked);
|
||||
}
|
||||
|
||||
if (checked)
|
||||
emit selectToolSelected();
|
||||
updateDesignModeActions(SelectionToolMode);
|
||||
}
|
||||
|
||||
void QmlJsInspectorToolBar::zoomToolTriggered(bool checked)
|
||||
{
|
||||
if (m_designModeActive != checked) {
|
||||
m_designModeActive = checked;
|
||||
emit designModeSelected(checked);
|
||||
}
|
||||
|
||||
if (checked)
|
||||
emit zoomToolSelected();
|
||||
|
||||
updateDesignModeActions(ZoomMode);
|
||||
}
|
||||
|
||||
void QmlJsInspectorToolBar::showAppOnTopClick()
|
||||
{
|
||||
if (m_emitSignals)
|
||||
emit showAppOnTopSelected(m_showAppOnTopAction->isChecked());
|
||||
}
|
||||
|
||||
void QmlJsInspectorToolBar::activateFromQml()
|
||||
{
|
||||
if (m_emitSignals)
|
||||
emit applyChangesFromQmlFileTriggered(m_fromQmlAction->isChecked());
|
||||
}
|
||||
|
||||
void QmlJsInspectorToolBar::updateDesignModeActions(DesignTool activeTool)
|
||||
{
|
||||
m_activeTool = activeTool;
|
||||
m_selectAction->setChecked(m_designModeActive
|
||||
&& (m_activeTool == SelectionToolMode));
|
||||
m_zoomAction->setChecked(m_designModeActive
|
||||
&& (m_activeTool == ZoomMode));
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSInspector
|
@@ -1,147 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef QMLJSINSPECTORTOOLBAR_H
|
||||
#define QMLJSINSPECTORTOOLBAR_H
|
||||
|
||||
#include <debugger/debuggerconstants.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QIcon>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QAction;
|
||||
class QActionGroup;
|
||||
class QToolButton;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace Utils {
|
||||
class StyledBar;
|
||||
class SavedAction;
|
||||
}
|
||||
|
||||
namespace QmlJSInspector {
|
||||
|
||||
namespace Internal {
|
||||
|
||||
class QmlJsInspectorToolBar : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum DesignTool {
|
||||
NoTool = 0,
|
||||
SelectionToolMode = 1,
|
||||
MarqueeSelectionToolMode = 2,
|
||||
MoveToolMode = 3,
|
||||
ResizeToolMode = 4,
|
||||
ZoomMode = 6
|
||||
};
|
||||
|
||||
explicit QmlJsInspectorToolBar(QObject *parent = 0);
|
||||
void createActions();
|
||||
QWidget *widget() const;
|
||||
void readSettings();
|
||||
void setZoomToolEnabled(bool enable);
|
||||
|
||||
public slots:
|
||||
void writeSettings() const;
|
||||
void setEnabled(bool value);
|
||||
void enable();
|
||||
void disable();
|
||||
|
||||
void activateSelectTool();
|
||||
void activateZoomTool();
|
||||
|
||||
void setAnimationSpeed(qreal slowDownFactor);
|
||||
void setAnimationPaused(bool paused);
|
||||
|
||||
void setDesignModeBehavior(bool inDesignMode);
|
||||
void setShowAppOnTop(bool showAppOnTop);
|
||||
|
||||
signals:
|
||||
void applyChangesFromQmlFileTriggered(bool isChecked);
|
||||
|
||||
void designModeSelected(bool);
|
||||
void reloadSelected();
|
||||
void selectToolSelected();
|
||||
void zoomToolSelected();
|
||||
|
||||
void showAppOnTopSelected(bool isChecked);
|
||||
|
||||
void animationSpeedChanged(qreal slowdownFactor);
|
||||
void animationPausedChanged(bool paused);
|
||||
|
||||
private slots:
|
||||
void activatePlayOnClick();
|
||||
void selectToolTriggered(bool checked);
|
||||
void zoomToolTriggered(bool checked);
|
||||
|
||||
void showAppOnTopClick();
|
||||
|
||||
void changeAnimationSpeed();
|
||||
|
||||
void activateFromQml();
|
||||
|
||||
void updatePlayAction();
|
||||
|
||||
private:
|
||||
void updateDesignModeActions(DesignTool activeTool);
|
||||
|
||||
Utils::SavedAction *m_fromQmlAction;
|
||||
QAction *m_playAction;
|
||||
QAction *m_selectAction;
|
||||
QAction *m_zoomAction;
|
||||
|
||||
Utils::SavedAction *m_showAppOnTopAction;
|
||||
|
||||
QActionGroup *m_playSpeedMenuActions;
|
||||
|
||||
QToolButton *m_playButton;
|
||||
QIcon m_playIcon;
|
||||
QIcon m_pauseIcon;
|
||||
|
||||
bool m_emitSignals;
|
||||
bool m_paused;
|
||||
qreal m_animationSpeed;
|
||||
|
||||
bool m_designModeActive;
|
||||
DesignTool m_activeTool;
|
||||
|
||||
QWidget *m_barWidget;
|
||||
bool m_zoomActionEnable;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlJSInspector
|
||||
|
||||
#endif // QMLJSINSPECTORTOOLBAR_H
|
@@ -1,627 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
#include "qmljspropertyinspector.h"
|
||||
#include "qmljsinspectorconstants.h"
|
||||
|
||||
#include <debugger/debuggerconstants.h>
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
#include <coreplugin/icore.h>
|
||||
|
||||
#include <QHeaderView>
|
||||
#include <QItemDelegate>
|
||||
#include <QLineEdit>
|
||||
#include <QDoubleValidator>
|
||||
#include <QPainter>
|
||||
|
||||
// expression editor
|
||||
#include <QContextMenuEvent>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
// context menu
|
||||
#include <QAction>
|
||||
#include <QMenu>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/savedaction.h>
|
||||
|
||||
const int PROPERTY_NAME_COLUMN = 0;
|
||||
const int PROPERTY_TYPE_COLUMN = 1;
|
||||
const int PROPERTY_VALUE_COLUMN = 2;
|
||||
|
||||
namespace QmlJSInspector {
|
||||
namespace Internal {
|
||||
|
||||
// *************************************************************************
|
||||
// PropertyEdit
|
||||
// *************************************************************************
|
||||
|
||||
class PropertyEditDelegate : public QItemDelegate
|
||||
{
|
||||
public:
|
||||
explicit PropertyEditDelegate(QObject *parent=0) : QItemDelegate(parent),
|
||||
m_treeWidget(dynamic_cast<QmlJSPropertyInspector *>(parent)) {}
|
||||
|
||||
QWidget *createEditor(QWidget *parent,
|
||||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
Q_UNUSED(option);
|
||||
if (index.column() != PROPERTY_VALUE_COLUMN)
|
||||
return 0;
|
||||
|
||||
switch (m_treeWidget->getTypeFor(index.row())) {
|
||||
|
||||
case QmlJSPropertyInspector::BooleanType: {
|
||||
// invert the bool, skip editor
|
||||
int objectId = m_treeWidget->getData(index.row(),
|
||||
PROPERTY_NAME_COLUMN,
|
||||
Qt::UserRole).toInt();
|
||||
QString propertyName
|
||||
= m_treeWidget->getData(index.row(),
|
||||
PROPERTY_NAME_COLUMN,
|
||||
Qt::DisplayRole).toString();
|
||||
bool propertyValue
|
||||
= m_treeWidget->getData(index.row(), PROPERTY_VALUE_COLUMN,
|
||||
Qt::DisplayRole).toBool();
|
||||
m_treeWidget->propertyValueEdited(objectId, propertyName,
|
||||
!propertyValue?"true":"false",
|
||||
true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
case QmlJSPropertyInspector::NumberType: {
|
||||
QLineEdit *editor = new QLineEdit(parent);
|
||||
editor->setValidator(new QDoubleValidator(editor));
|
||||
return editor;
|
||||
}
|
||||
|
||||
default: {
|
||||
return new QLineEdit(parent);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void setEditorData(QWidget *editor, const QModelIndex &index) const
|
||||
{
|
||||
QVariant data = m_treeWidget->getData(index.row(), PROPERTY_VALUE_COLUMN,
|
||||
Qt::DisplayRole);
|
||||
QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
|
||||
lineEdit->setText(data.toString());
|
||||
}
|
||||
|
||||
void setModelData(QWidget *editor, QAbstractItemModel *model,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
Q_UNUSED(model);
|
||||
|
||||
int objectId = m_treeWidget->getData(index.row(), PROPERTY_NAME_COLUMN,
|
||||
Qt::UserRole).toInt();
|
||||
if (objectId == -1)
|
||||
return;
|
||||
|
||||
QString propertyName = m_treeWidget->getData(index.row(),
|
||||
PROPERTY_NAME_COLUMN,
|
||||
Qt::DisplayRole).toString();
|
||||
QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
|
||||
QString propertyValue = lineEdit->text();
|
||||
m_treeWidget->propertyValueEdited(objectId, propertyName, propertyValue,
|
||||
true);
|
||||
lineEdit->clearFocus();
|
||||
}
|
||||
|
||||
void updateEditorGeometry(QWidget *editor,
|
||||
const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
Q_UNUSED(index);
|
||||
QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
|
||||
lineEdit->setGeometry(option.rect);
|
||||
}
|
||||
|
||||
private:
|
||||
QmlJSPropertyInspector *m_treeWidget;
|
||||
|
||||
};
|
||||
// *************************************************************************
|
||||
// expressionEdit
|
||||
// *************************************************************************
|
||||
|
||||
ExpressionEdit::ExpressionEdit(const QString &title, QDialog *parent)
|
||||
: QDialog(parent)
|
||||
, m_buttonBox(new QDialogButtonBox(QDialogButtonBox::Ok
|
||||
| QDialogButtonBox::Cancel))
|
||||
, m_exprInput(new QLineEdit(this))
|
||||
{
|
||||
setWindowTitle(title);
|
||||
|
||||
QVBoxLayout *vertLayout = new QVBoxLayout;
|
||||
m_exprInput->setMinimumWidth(550);
|
||||
connect(m_exprInput,SIGNAL(returnPressed()),this,SLOT(accept()));
|
||||
vertLayout->addWidget(m_exprInput);
|
||||
vertLayout->addWidget(m_buttonBox);
|
||||
setLayout(vertLayout);
|
||||
|
||||
connect(m_buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
|
||||
connect(m_buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
|
||||
}
|
||||
|
||||
QString ExpressionEdit::expression() const
|
||||
{
|
||||
return m_exprInput->text();
|
||||
}
|
||||
|
||||
void ExpressionEdit::setItemData(int objectId, const QString &propertyName)
|
||||
{
|
||||
m_debugId = objectId;
|
||||
m_paramName = propertyName;
|
||||
}
|
||||
|
||||
void ExpressionEdit::accept()
|
||||
{
|
||||
QDialog::accept();
|
||||
emit dataChanged(m_debugId, m_paramName, expression());
|
||||
}
|
||||
|
||||
// *************************************************************************
|
||||
// color chooser
|
||||
// *************************************************************************
|
||||
|
||||
inline QString extendedNameFromColor(QColor color)
|
||||
{
|
||||
int alphaValue = color.alpha();
|
||||
if (alphaValue < 255)
|
||||
return QLatin1String("#")
|
||||
+ QString("%1").arg(alphaValue, 2, 16, QChar('0'))
|
||||
+ color.name().right(6) ;
|
||||
else
|
||||
return color.name();
|
||||
}
|
||||
|
||||
inline QString extendedNameFromColor(QVariant color) {
|
||||
return extendedNameFromColor(QColor(color.value<QColor>()));
|
||||
}
|
||||
|
||||
inline QColor colorFromExtendedName(QString name) {
|
||||
QRegExp validator("#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})");
|
||||
if (validator.exactMatch(name)) {
|
||||
return QColor(validator.cap(2).toInt(0,16),
|
||||
validator.cap(3).toInt(0,16),
|
||||
validator.cap(4).toInt(0,16),
|
||||
validator.cap(1).toInt(0,16));
|
||||
}
|
||||
return QColor(name);
|
||||
}
|
||||
|
||||
ColorChooserDialog::ColorChooserDialog(const QString &title, QDialog *parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
setWindowTitle(title);
|
||||
|
||||
QVBoxLayout *vertLayout = new QVBoxLayout;
|
||||
m_mainFrame = new QmlEditorWidgets::CustomColorDialog(this);
|
||||
setLayout(vertLayout);
|
||||
|
||||
setFixedSize(m_mainFrame->size());
|
||||
|
||||
connect(m_mainFrame,SIGNAL(accepted(QColor)),this,SLOT(acceptColor(QColor)));
|
||||
connect(m_mainFrame,SIGNAL(rejected()),this,SLOT(reject()));
|
||||
}
|
||||
|
||||
void ColorChooserDialog::setItemData(int objectId, const QString &propertyName,
|
||||
const QString &colorName)
|
||||
{
|
||||
m_debugId = objectId;
|
||||
m_paramName = propertyName;
|
||||
m_mainFrame->setColor(QColor(colorName));
|
||||
}
|
||||
|
||||
void ColorChooserDialog::acceptColor(const QColor &color)
|
||||
{
|
||||
QDialog::accept();
|
||||
emit dataChanged(m_debugId, m_paramName,
|
||||
QChar('\"') + color.name() + QChar('\"'));
|
||||
}
|
||||
|
||||
// *************************************************************************
|
||||
// QmlJSObjectTree
|
||||
// *************************************************************************
|
||||
inline QString cleanPropertyValue(QString propertyValue)
|
||||
{
|
||||
if (propertyValue == QString("<unknown value>"))
|
||||
return QString();
|
||||
if (propertyValue == QString("<unnamed object>"))
|
||||
return QString();
|
||||
return propertyValue;
|
||||
}
|
||||
|
||||
// *************************************************************************
|
||||
// QmlJSPropertyInspectorModel
|
||||
// *************************************************************************
|
||||
QmlJSPropertyInspectorModel::QmlJSPropertyInspectorModel()
|
||||
: QStandardItemModel()
|
||||
, m_contentsValid(false)
|
||||
{
|
||||
}
|
||||
|
||||
Qt::ItemFlags QmlJSPropertyInspectorModel::flags(const QModelIndex &index) const
|
||||
{
|
||||
return m_contentsValid ? QStandardItemModel::flags(index) : Qt::ItemFlags();
|
||||
}
|
||||
|
||||
QVariant QmlJSPropertyInspectorModel::headerData(
|
||||
int section, Qt::Orientation orient, int role) const
|
||||
{
|
||||
if (orient == Qt::Horizontal && role == Qt::DisplayRole) {
|
||||
switch (section) {
|
||||
case PROPERTY_NAME_COLUMN: return tr("Name");
|
||||
case PROPERTY_VALUE_COLUMN: return tr("Value");
|
||||
case PROPERTY_TYPE_COLUMN: return tr("Type");
|
||||
};
|
||||
}
|
||||
return QStandardItemModel::headerData(section, orient, role);
|
||||
}
|
||||
|
||||
void QmlJSPropertyInspectorModel::setContentsValid(bool contentsValid)
|
||||
{
|
||||
m_contentsValid = contentsValid;
|
||||
}
|
||||
|
||||
bool QmlJSPropertyInspectorModel::contentsValid() const
|
||||
{
|
||||
return m_contentsValid;
|
||||
}
|
||||
|
||||
QmlJSPropertyInspector::QmlJSPropertyInspector(QWidget *parent)
|
||||
: Utils::BaseTreeView(parent)
|
||||
{
|
||||
setItemDelegateForColumn(PROPERTY_VALUE_COLUMN,
|
||||
new PropertyEditDelegate(this));
|
||||
|
||||
setModel(&m_model);
|
||||
//Add an empty Row to make the headers visible!
|
||||
addRow(QString(), QString(), QString(), -1, false);
|
||||
|
||||
m_adjustColumnsAction = new Utils::SavedAction(this);
|
||||
m_adjustColumnsAction->setText(tr("Always Adjust Column Widths to Contents"));
|
||||
m_adjustColumnsAction->setCheckable(true);
|
||||
m_adjustColumnsAction->setValue(false);
|
||||
m_adjustColumnsAction->setDefaultValue(false);
|
||||
m_adjustColumnsAction->setSettingsKey(QLatin1String(Constants::S_QML_INSPECTOR),
|
||||
QLatin1String(Constants::ALWAYS_ADJUST_COLUMNS_WIDTHS));
|
||||
readSettings();
|
||||
connect(Core::ICore::instance(),
|
||||
SIGNAL(saveSettingsRequested()), SLOT(writeSettings()));
|
||||
|
||||
setAlwaysAdjustColumnsAction(m_adjustColumnsAction);
|
||||
|
||||
QAction *act = qobject_cast<QAction *>(
|
||||
ExtensionSystem::PluginManager::instance()->getObjectByName(
|
||||
QLatin1String(Debugger::Constants::USE_ALTERNATING_ROW_COLORS)));
|
||||
if (act) {
|
||||
setAlternatingRowColors(act->isChecked());
|
||||
connect(act, SIGNAL(toggled(bool)),
|
||||
SLOT(setAlternatingRowColorsHelper(bool)));
|
||||
}
|
||||
}
|
||||
|
||||
void QmlJSPropertyInspector::readSettings()
|
||||
{
|
||||
QSettings *settings = Core::ICore::settings();
|
||||
m_adjustColumnsAction->readSettings(settings);
|
||||
}
|
||||
|
||||
void QmlJSPropertyInspector::writeSettings() const
|
||||
{
|
||||
QSettings *settings = Core::ICore::settings();
|
||||
m_adjustColumnsAction->writeSettings(settings);
|
||||
}
|
||||
|
||||
void QmlJSPropertyInspector::addBaseContextActions(QMenu *menu)
|
||||
{
|
||||
QAction *act = qobject_cast<QAction *>(
|
||||
ExtensionSystem::PluginManager::instance()->getObjectByName(
|
||||
QLatin1String(Debugger::Constants::SORT_STRUCT_MEMBERS)));
|
||||
if (act)
|
||||
menu->addAction(act);
|
||||
Utils::BaseTreeView::addBaseContextActions(menu);
|
||||
|
||||
act = qobject_cast<QAction *>(
|
||||
ExtensionSystem::PluginManager::instance()->getObjectByName(
|
||||
QLatin1String(Debugger::Constants::SETTINGS_DIALOG)));
|
||||
if (act)
|
||||
menu->addAction(act);
|
||||
}
|
||||
|
||||
void QmlJSPropertyInspector::clear()
|
||||
{
|
||||
m_model.removeRows(0, m_model.rowCount());
|
||||
m_currentObjects.clear();
|
||||
}
|
||||
|
||||
void QmlJSPropertyInspector::setContentsValid(bool contentsValid)
|
||||
{
|
||||
m_model.setContentsValid(contentsValid);
|
||||
}
|
||||
|
||||
bool QmlJSPropertyInspector::contentsValid() const
|
||||
{
|
||||
return m_model.contentsValid();
|
||||
}
|
||||
|
||||
void QmlJSPropertyInspector::setCurrentObjects(
|
||||
const QList<QmlDebugObjectReference> &objectList)
|
||||
{
|
||||
if (objectList.isEmpty())
|
||||
return;
|
||||
|
||||
clear();
|
||||
|
||||
foreach (const QmlDebugObjectReference &obj, objectList) {
|
||||
m_currentObjects << obj.debugId();
|
||||
buildPropertyTree(obj);
|
||||
}
|
||||
}
|
||||
|
||||
QVariant QmlJSPropertyInspector::getData(int row, int column, int role) const
|
||||
{
|
||||
return m_model.data(m_model.index(row, column), role);
|
||||
}
|
||||
|
||||
QmlJSPropertyInspector::PropertyType
|
||||
QmlJSPropertyInspector::getTypeFor(int row) const
|
||||
{
|
||||
return static_cast<QmlJSPropertyInspector::PropertyType>(
|
||||
m_model.data(m_model.index(row, PROPERTY_TYPE_COLUMN),
|
||||
Qt::UserRole).toInt());
|
||||
}
|
||||
|
||||
void QmlJSPropertyInspector::propertyValueChanged(int debugId,
|
||||
const QByteArray &propertyName,
|
||||
const QVariant &propertyValue)
|
||||
{
|
||||
if (m_model.rowCount() == 0)
|
||||
return;
|
||||
|
||||
QString propertyNameS = QString(propertyName);
|
||||
for (int i = 0; i < m_model.rowCount(); i++) {
|
||||
if (m_model.data(m_model.index(i, PROPERTY_NAME_COLUMN),
|
||||
Qt::DisplayRole).toString() == propertyNameS &&
|
||||
m_model.data(m_model.index(i, PROPERTY_NAME_COLUMN),
|
||||
Qt::UserRole).toInt() == debugId) {
|
||||
QString oldData = m_model.data(m_model.index(i, PROPERTY_VALUE_COLUMN),
|
||||
Qt::DisplayRole).toString();
|
||||
QString newData = propertyValue.toString();
|
||||
if (QString(propertyValue.typeName()) == "QColor")
|
||||
newData = extendedNameFromColor(propertyValue);
|
||||
if (oldData != newData) {
|
||||
m_model.setData(m_model.index(i, PROPERTY_VALUE_COLUMN), newData,
|
||||
Qt::DisplayRole);
|
||||
m_model.item(i, PROPERTY_VALUE_COLUMN)->setToolTip(newData);
|
||||
m_model.item(i, PROPERTY_NAME_COLUMN)->setForeground(QBrush(Qt::red));
|
||||
m_model.item(i, PROPERTY_VALUE_COLUMN)->setForeground(QBrush(Qt::red));
|
||||
m_model.item(i, PROPERTY_TYPE_COLUMN)->setForeground(QBrush(Qt::red));
|
||||
if (getTypeFor(i) == QmlJSPropertyInspector::ColorType)
|
||||
setColorIcon(i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QmlJSPropertyInspector::propertyValueEdited(const int objectId,
|
||||
const QString &propertyName,
|
||||
const QString &propertyValue,
|
||||
bool isLiteral)
|
||||
{
|
||||
emit changePropertyValue(objectId, propertyName, propertyValue, isLiteral);
|
||||
}
|
||||
|
||||
void QmlJSPropertyInspector::buildPropertyTree(const QmlDebugObjectReference &obj)
|
||||
{
|
||||
// Strip off the misleading metadata
|
||||
QString objTypeName = obj.className();
|
||||
QString declarativeString("QDeclarative");
|
||||
if (objTypeName.startsWith(declarativeString)) {
|
||||
objTypeName = objTypeName.mid(declarativeString.length()).section('_',
|
||||
0, 0);
|
||||
}
|
||||
|
||||
// class
|
||||
addRow(QString("class"),
|
||||
objTypeName,
|
||||
QString("qmlType"),
|
||||
obj.debugId(),
|
||||
false);
|
||||
|
||||
// id
|
||||
if (!obj.idString().isEmpty()) {
|
||||
addRow(QString("id"),
|
||||
obj.idString(),
|
||||
QString("idString"),
|
||||
obj.debugId(),
|
||||
false);
|
||||
}
|
||||
|
||||
foreach (const QmlDebugPropertyReference &prop, obj.properties()) {
|
||||
QString propertyName = prop.name();
|
||||
QString propertyValue = prop.value().toString();
|
||||
|
||||
if (cleanPropertyValue(propertyValue).isEmpty())
|
||||
continue;
|
||||
|
||||
if (prop.valueTypeName() == "QColor") {
|
||||
propertyValue = extendedNameFromColor(prop.value());
|
||||
}
|
||||
|
||||
addRow(propertyName, propertyValue, prop.valueTypeName(), obj.debugId(),
|
||||
prop.hasNotifySignal());
|
||||
}
|
||||
|
||||
m_model.setHeaderData(PROPERTY_NAME_COLUMN, Qt::Horizontal,QVariant("name"));
|
||||
m_model.setHeaderData(PROPERTY_VALUE_COLUMN, Qt::Horizontal,QVariant("value"));
|
||||
m_model.setHeaderData(PROPERTY_TYPE_COLUMN, Qt::Horizontal,QVariant("type"));
|
||||
|
||||
QAction *act = qobject_cast<QAction *>(
|
||||
ExtensionSystem::PluginManager::instance()->getObjectByName(
|
||||
QLatin1String(Debugger::Constants::SORT_STRUCT_MEMBERS)));
|
||||
if (act && act->isChecked())
|
||||
m_model.sort(PROPERTY_NAME_COLUMN);
|
||||
}
|
||||
|
||||
void QmlJSPropertyInspector::addRow(const QString &name,const QString &value,
|
||||
const QString &type, const int debugId,
|
||||
bool editable)
|
||||
{
|
||||
QStandardItem *nameColumn = new QStandardItem(name);
|
||||
nameColumn->setToolTip(name);
|
||||
nameColumn->setData(QVariant(debugId),Qt::UserRole);
|
||||
nameColumn->setEditable(false);
|
||||
|
||||
QStandardItem *valueColumn = new QStandardItem(value);
|
||||
valueColumn->setToolTip(value);
|
||||
valueColumn->setEditable(editable);
|
||||
valueColumn->setData(QVariant(editable),Qt::UserRole+1);
|
||||
|
||||
QStandardItem *typeColumn = new QStandardItem(type);
|
||||
typeColumn->setToolTip(type);
|
||||
typeColumn->setEditable(false);
|
||||
|
||||
// encode type for easy lookup
|
||||
QmlJSPropertyInspector::PropertyType typeCode
|
||||
= QmlJSPropertyInspector::OtherType;
|
||||
if (type == "bool")
|
||||
typeCode = QmlJSPropertyInspector::BooleanType;
|
||||
else if (type == "qreal")
|
||||
typeCode = QmlJSPropertyInspector::NumberType;
|
||||
else if (type == "QString")
|
||||
typeCode = QmlJSPropertyInspector::StringType;
|
||||
else if (type == "QColor")
|
||||
typeCode = QmlJSPropertyInspector::ColorType;
|
||||
|
||||
typeColumn->setData(typeCode, Qt::UserRole);
|
||||
|
||||
QList<QStandardItem *> newRow;
|
||||
newRow << nameColumn << typeColumn << valueColumn;
|
||||
m_model.appendRow(newRow);
|
||||
|
||||
if (typeCode == QmlJSPropertyInspector::ColorType)
|
||||
setColorIcon(m_model.indexFromItem(valueColumn).row());
|
||||
}
|
||||
|
||||
void QmlJSPropertyInspector::setColorIcon(int row)
|
||||
{
|
||||
QStandardItem *item = m_model.item(row, PROPERTY_VALUE_COLUMN);
|
||||
QColor color = colorFromExtendedName(item->data(Qt::DisplayRole).toString());
|
||||
|
||||
int recomendedLength = viewOptions().decorationSize.height() - 2;
|
||||
|
||||
QPixmap colorpix(recomendedLength, recomendedLength);
|
||||
QPainter p(&colorpix);
|
||||
if (color.alpha() != 255)
|
||||
p.fillRect(1,1, recomendedLength -2, recomendedLength - 2, Qt::white);
|
||||
p.fillRect(1, 1, recomendedLength - 2, recomendedLength - 2, color);
|
||||
p.setPen(Qt::black);
|
||||
p.drawRect(0, 0, recomendedLength - 1, recomendedLength - 1);
|
||||
item->setIcon(colorpix);
|
||||
}
|
||||
|
||||
void QmlJSPropertyInspector::contextMenuEvent(QContextMenuEvent *ev)
|
||||
{
|
||||
QMenu menu;
|
||||
QModelIndex itemIndex = indexAt(ev->pos());
|
||||
bool isEditable = false;
|
||||
bool isColor = false;
|
||||
if (itemIndex.isValid()) {
|
||||
isEditable = m_model.item(itemIndex.row(), PROPERTY_VALUE_COLUMN)->isEditable();
|
||||
isColor = (getTypeFor(itemIndex.row()) == QmlJSPropertyInspector::ColorType);
|
||||
}
|
||||
|
||||
QAction exprAction(tr("Enter expression"), this);
|
||||
if (isEditable)
|
||||
menu.addAction(&exprAction);
|
||||
|
||||
QAction colorAction(tr("Choose color"), this);
|
||||
if (isColor)
|
||||
menu.addAction(&colorAction);
|
||||
addBaseContextActions(&menu);
|
||||
|
||||
QAction *action = menu.exec(ev->globalPos());
|
||||
if (action == 0)
|
||||
return;
|
||||
|
||||
if (action == &exprAction)
|
||||
openExpressionEditor(itemIndex);
|
||||
if (action == &colorAction)
|
||||
openColorSelector(itemIndex);
|
||||
handleBaseContextAction(action);
|
||||
}
|
||||
|
||||
void QmlJSPropertyInspector::openExpressionEditor(const QModelIndex &itemIndex)
|
||||
{
|
||||
const QString propertyName = getData(itemIndex.row(), PROPERTY_NAME_COLUMN,
|
||||
Qt::DisplayRole).toString();
|
||||
const QString dialogText = tr("JavaScript expression for %1").arg(propertyName);
|
||||
const int objectId = getData(itemIndex.row(), PROPERTY_NAME_COLUMN,
|
||||
Qt::UserRole).toInt();
|
||||
|
||||
ExpressionEdit *expressionDialog = new ExpressionEdit(dialogText);
|
||||
expressionDialog->setItemData(objectId, propertyName);
|
||||
|
||||
connect(expressionDialog, SIGNAL(dataChanged(int,QString,QString)),
|
||||
this, SLOT(propertyValueEdited(int,QString,QString)));
|
||||
|
||||
expressionDialog->show();
|
||||
}
|
||||
|
||||
void QmlJSPropertyInspector::openColorSelector(const QModelIndex &itemIndex)
|
||||
{
|
||||
const QString propertyName = getData(itemIndex.row(), PROPERTY_NAME_COLUMN,
|
||||
Qt::DisplayRole).toString();
|
||||
const QString dialogText = tr("Color selection for %1").arg(propertyName);
|
||||
const int objectId = getData(itemIndex.row(), PROPERTY_NAME_COLUMN,
|
||||
Qt::UserRole).toInt();
|
||||
const QString propertyValue = getData(itemIndex.row(), PROPERTY_VALUE_COLUMN,
|
||||
Qt::DisplayRole).toString();
|
||||
|
||||
ColorChooserDialog *colorDialog = new ColorChooserDialog(dialogText);
|
||||
colorDialog->setItemData(objectId, propertyName, propertyValue);
|
||||
|
||||
connect(colorDialog, SIGNAL(dataChanged(int,QString,QString)),
|
||||
this, SLOT(propertyValueEdited(int,QString,QString)));
|
||||
|
||||
colorDialog->show();
|
||||
}
|
||||
|
||||
} // Internal
|
||||
} // QmlJSInspector
|
@@ -1,172 +0,0 @@
|
||||
/**************************************************************************
|
||||
**
|
||||
** This file is part of Qt Creator
|
||||
**
|
||||
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
||||
**
|
||||
** Contact: Nokia Corporation (qt-info@nokia.com)
|
||||
**
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
**
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this file.
|
||||
** Please review the following information to ensure the GNU Lesser General
|
||||
** Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** Other Usage
|
||||
**
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
** If you have questions regarding the use of this file, please contact
|
||||
** Nokia at qt-info@nokia.com.
|
||||
**
|
||||
**************************************************************************/
|
||||
#ifndef PROPERTYINSPECTOR_H
|
||||
#define PROPERTYINSPECTOR_H
|
||||
|
||||
#include <qmldebug/baseenginedebugclient.h>
|
||||
#include <utils/basetreeview.h>
|
||||
#include <QStandardItemModel>
|
||||
|
||||
#include <QDialog>
|
||||
#include <QDialogButtonBox>
|
||||
|
||||
#include "customcolordialog.h"
|
||||
|
||||
using namespace QmlDebug;
|
||||
|
||||
namespace Utils {
|
||||
class SavedAction;
|
||||
}
|
||||
|
||||
namespace QmlJSInspector {
|
||||
namespace Internal {
|
||||
|
||||
class PropertyEditDelegate;
|
||||
|
||||
class ExpressionEdit : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ExpressionEdit(const QString &title, QDialog *parent = 0);
|
||||
|
||||
QString expression() const;
|
||||
void setItemData(int objectId, const QString &propertyName);
|
||||
|
||||
virtual void accept();
|
||||
|
||||
signals:
|
||||
void dataChanged(int debugId, const QString ¶mName,
|
||||
const QString &newExpression);
|
||||
|
||||
private:
|
||||
QDialogButtonBox *m_buttonBox;
|
||||
QLineEdit *m_exprInput;
|
||||
int m_debugId;
|
||||
QString m_paramName;
|
||||
};
|
||||
|
||||
class ColorChooserDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ColorChooserDialog(const QString &title, QDialog *parent = 0);
|
||||
|
||||
void setItemData(int objectId,const QString &propertyName,
|
||||
const QString &colorName);
|
||||
|
||||
public slots:
|
||||
void acceptColor(const QColor &color);
|
||||
|
||||
signals:
|
||||
void dataChanged(int debugId, const QString ¶mName,
|
||||
const QString &newExpression);
|
||||
|
||||
|
||||
private:
|
||||
int m_debugId;
|
||||
QString m_paramName;
|
||||
QmlEditorWidgets::CustomColorDialog *m_mainFrame;
|
||||
};
|
||||
|
||||
class QmlJSPropertyInspectorModel : public QStandardItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QmlJSPropertyInspectorModel();
|
||||
void setContentsValid(bool contentsValid);
|
||||
bool contentsValid() const;
|
||||
|
||||
protected:
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
|
||||
|
||||
private:
|
||||
bool m_contentsValid;
|
||||
};
|
||||
|
||||
class QmlJSPropertyInspector : public Utils::BaseTreeView
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum PropertyType
|
||||
{
|
||||
BooleanType,
|
||||
NumberType,
|
||||
StringType,
|
||||
ColorType,
|
||||
OtherType
|
||||
};
|
||||
|
||||
explicit QmlJSPropertyInspector(QWidget *parent = 0);
|
||||
void readSettings();
|
||||
void addBaseContextActions(QMenu *menu);
|
||||
void clear();
|
||||
void setContentsValid(bool contentsValid);
|
||||
bool contentsValid() const;
|
||||
|
||||
signals:
|
||||
void changePropertyValue(int debugId, QString propertyName,
|
||||
QString valueExpression, bool isLiteral);
|
||||
void customContextMenuRequested(const QPoint &pos);
|
||||
|
||||
public slots:
|
||||
void writeSettings() const;
|
||||
void setCurrentObjects(const QList<QmlDebugObjectReference> &);
|
||||
void propertyValueEdited(const int objectId,const QString &propertyName,
|
||||
const QString &propertyValue, bool isLiteral = false);
|
||||
void propertyValueChanged(int debugId, const QByteArray &propertyName,
|
||||
const QVariant &propertyValue);
|
||||
|
||||
void openExpressionEditor(const QModelIndex &itemIndex);
|
||||
void openColorSelector(const QModelIndex &itemIndex);
|
||||
|
||||
private:
|
||||
friend class PropertyEditDelegate;
|
||||
void buildPropertyTree(const QmlDebugObjectReference &);
|
||||
void addRow(const QString &name, const QString &value, const QString &type,
|
||||
const int debugId = -1, bool editable = true);
|
||||
void setColorIcon(int row);
|
||||
|
||||
QVariant getData(int row, int column, int role) const;
|
||||
QmlJSPropertyInspector::PropertyType getTypeFor(int row) const;
|
||||
|
||||
void contextMenuEvent(QContextMenuEvent *ev);
|
||||
|
||||
QmlJSPropertyInspectorModel m_model;
|
||||
QList<int> m_currentObjects;
|
||||
Utils::SavedAction *m_adjustColumnsAction;
|
||||
};
|
||||
|
||||
} // Internal
|
||||
} // QmlJSInspector
|
||||
|
||||
#endif
|