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>
This commit is contained in:
Kai Koehne
2012-04-18 14:20:54 +02:00
parent d201c681da
commit 7f09d0b756
80 changed files with 2669 additions and 5187 deletions

View File

@@ -55,7 +55,6 @@ Project {
"src/plugins/projectexplorer/projectexplorer.qbs", "src/plugins/projectexplorer/projectexplorer.qbs",
"src/plugins/qmldesigner/qmldesigner.qbs", "src/plugins/qmldesigner/qmldesigner.qbs",
"src/plugins/qmljseditor/qmljseditor.qbs", "src/plugins/qmljseditor/qmljseditor.qbs",
"src/plugins/qmljsinspector/qmljsinspector.qbs",
"src/plugins/qmljstools/qmljstools.qbs", "src/plugins/qmljstools/qmljstools.qbs",
"src/plugins/qmlprofiler/qmlprofiler.qbs", "src/plugins/qmlprofiler/qmlprofiler.qbs",
"src/plugins/qmlprojectmanager/qmlprojectmanager.qbs", "src/plugins/qmlprojectmanager/qmlprojectmanager.qbs",

View File

@@ -348,14 +348,16 @@ quint32 BaseEngineDebugClient::queryObjectRecursive(const QmlDebugObjectReferenc
} }
quint32 BaseEngineDebugClient::queryExpressionResult(int objectDebugId, quint32 BaseEngineDebugClient::queryExpressionResult(int objectDebugId,
const QString &expr) const QString &expr,
int engineId)
{ {
quint32 id = 0; quint32 id = 0;
if (status() == QmlDebugClient::Enabled && objectDebugId != -1) { if (status() == QmlDebugClient::Enabled && objectDebugId != -1) {
id = getId(); id = getId();
QByteArray message; QByteArray message;
QDataStream ds(&message, QIODevice::WriteOnly); QDataStream ds(&message, QIODevice::WriteOnly);
ds << QByteArray("EVAL_EXPRESSION") << id << objectDebugId << expr; ds << QByteArray("EVAL_EXPRESSION") << id << objectDebugId << expr
<< engineId;
sendMessage(message); sendMessage(message);
} }
return id; return id;

View File

@@ -66,7 +66,7 @@ public:
quint32 queryObject(const QmlDebugObjectReference &object); quint32 queryObject(const QmlDebugObjectReference &object);
quint32 queryObjectRecursive(const QmlDebugObjectReference &object); quint32 queryObjectRecursive(const QmlDebugObjectReference &object);
quint32 queryExpressionResult(int objectDebugId, quint32 queryExpressionResult(int objectDebugId,
const QString &expr); const QString &expr, int engineId = -1);
virtual quint32 setBindingForObject(int objectDebugId, const QString &propertyName, virtual quint32 setBindingForObject(int objectDebugId, const QString &propertyName,
const QVariant &bindingExpression, const QVariant &bindingExpression,
bool isLiteralValue, bool isLiteralValue,
@@ -116,7 +116,7 @@ class QmlDebugEngineReference
{ {
public: public:
QmlDebugEngineReference() : m_debugId(-1) {} QmlDebugEngineReference() : m_debugId(-1) {}
QmlDebugEngineReference(int id) : m_debugId(id) {} explicit QmlDebugEngineReference(int id) : m_debugId(id) {}
int debugId() const { return m_debugId; } int debugId() const { return m_debugId; }
QString name() const { return m_name; } QString name() const { return m_name; }
@@ -133,7 +133,7 @@ class QmlDebugObjectReference
{ {
public: public:
QmlDebugObjectReference() : m_debugId(-1), m_parentId(-1), m_contextDebugId(-1), m_needsMoreData(false) {} 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 debugId() const { return m_debugId; }
int parentId() const { return m_parentId; } int parentId() const { return m_parentId; }
@@ -148,18 +148,18 @@ public:
QList<QmlDebugPropertyReference> properties() const { return m_properties; } QList<QmlDebugPropertyReference> properties() const { return m_properties; }
QList<QmlDebugObjectReference> children() const { return m_children; } 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++) { for (int i = 0; i < m_children.count(); i++) {
if (m_children[i].debugId() == obj.debugId()) { if (m_children[i].debugId() == obj.debugId()) {
m_children.replace(i, obj); m_children.replace(i, obj);
return true; return debugId();
} else { } else {
if (m_children[i].insertObjectInTree(obj)) if (m_children[i].insertObjectInTree(obj))
return true; return debugId();
} }
} }
return false; return -1;
} }
bool operator ==(const QmlDebugObjectReference &obj) bool operator ==(const QmlDebugObjectReference &obj)
@@ -229,4 +229,20 @@ Q_DECLARE_METATYPE(QmlDebug::QmlDebugEngineReference)
Q_DECLARE_METATYPE(QmlDebug::QmlDebugEngineReferenceList) Q_DECLARE_METATYPE(QmlDebug::QmlDebugEngineReferenceList)
Q_DECLARE_METATYPE(QmlDebug::QmlDebugContextReference) 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 #endif // BASEENGINEDEBUGCLIENT_H

View File

@@ -31,10 +31,9 @@
#include "basetoolsclient.h" #include "basetoolsclient.h"
namespace QmlJSInspector { namespace QmlDebug {
namespace Internal {
BaseToolsClient::BaseToolsClient(QmlDebug::QmlDebugConnection* client, QLatin1String clientName) BaseToolsClient::BaseToolsClient(QmlDebugConnection* client, QLatin1String clientName)
: QmlDebugClient(clientName, client) : QmlDebugClient(clientName, client)
{ {
setObjectName(clientName); setObjectName(clientName);
@@ -45,14 +44,13 @@ void BaseToolsClient::statusChanged(Status status)
emit connectedStatusChanged(status); emit connectedStatusChanged(status);
} }
void BaseToolsClient::recurseObjectIdList(const QmlDebug::QmlDebugObjectReference &ref, void BaseToolsClient::recurseObjectIdList(const QmlDebugObjectReference &ref,
QList<int> &debugIds, QList<QString> &objectIds) QList<int> &debugIds, QList<QString> &objectIds)
{ {
debugIds << ref.debugId(); debugIds << ref.debugId();
objectIds << ref.idString(); objectIds << ref.idString();
foreach (const QmlDebug::QmlDebugObjectReference &child, ref.children()) foreach (const QmlDebugObjectReference &child, ref.children())
recurseObjectIdList(child, debugIds, objectIds); recurseObjectIdList(child, debugIds, objectIds);
} }
} // namespace Internal } // namespace QmlDebug
} // namespace QmlJSInspector

View File

@@ -32,17 +32,16 @@
#ifndef BASETOOLSCLIENT_H #ifndef BASETOOLSCLIENT_H
#define BASETOOLSCLIENT_H #define BASETOOLSCLIENT_H
#include <qmldebug/qmldebugclient.h> #include "qmldebugclient.h"
#include <qmldebug/baseenginedebugclient.h> #include "baseenginedebugclient.h"
namespace QmlJSInspector { namespace QmlDebug {
namespace Internal {
class BaseToolsClient : public QmlDebug::QmlDebugClient class QMLDEBUG_EXPORT BaseToolsClient : public QmlDebugClient
{ {
Q_OBJECT Q_OBJECT
public: public:
BaseToolsClient(QmlDebug::QmlDebugConnection* client, QLatin1String clientName); BaseToolsClient(QmlDebugConnection *client, QLatin1String clientName);
virtual void setCurrentObjects(const QList<int> &debugIds) = 0; virtual void setCurrentObjects(const QList<int> &debugIds) = 0;
virtual void reloadViewer() = 0; virtual void reloadViewer() = 0;
@@ -67,7 +66,7 @@ public:
// ### Qt 4.8: remove if we can have access to qdeclarativecontextdata or id's // ### Qt 4.8: remove if we can have access to qdeclarativecontextdata or id's
virtual void setObjectIdList( virtual void setObjectIdList(
const QList<QmlDebug::QmlDebugObjectReference> &objectRoots) = 0; const QList<QmlDebugObjectReference> &objectRoots) = 0;
virtual void clearComponentCache() = 0; virtual void clearComponentCache() = 0;
@@ -89,7 +88,7 @@ signals:
protected: protected:
void statusChanged(Status); void statusChanged(Status);
void recurseObjectIdList(const QmlDebug::QmlDebugObjectReference &ref, void recurseObjectIdList(const QmlDebugObjectReference &ref,
QList<int> &debugIds, QList<QString> &objectIds); QList<int> &debugIds, QList<QString> &objectIds);
protected: protected:
enum LogDirection { enum LogDirection {
@@ -98,7 +97,6 @@ protected:
}; };
}; };
} // namespace Internal } // namespace QmlDebug
} // namespace QmlJSInspector
#endif // BASETOOLSCLIENT_H #endif // BASETOOLSCLIENT_H

View File

@@ -30,16 +30,114 @@
**************************************************************************/ **************************************************************************/
#include "declarativetoolsclient.h" #include "declarativetoolsclient.h"
#include "qmljsclientproxy.h" #include <QMetaEnum>
#include "qmljsinspectorconstants.h" #include <QStringList>
using namespace QmlJSDebugger; namespace QmlDebug {
namespace QmlJSInspector {
namespace Internal { 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) DeclarativeToolsClient::DeclarativeToolsClient(QmlDebugConnection *client)
: BaseToolsClient(client,QLatin1String(Constants::QDECLARATIVE_OBSERVER_MODE)), : BaseToolsClient(client,QLatin1String("QDeclarativeObserverMode")),
m_connection(client) m_connection(client)
{ {
setObjectName(name()); setObjectName(name());
@@ -165,7 +263,7 @@ void DeclarativeToolsClient::setCurrentObjects(const QList<int> &debugIds)
} }
void DeclarativeToolsClient::setObjectIdList( void DeclarativeToolsClient::setObjectIdList(
const QList<QmlDebug::QmlDebugObjectReference> &objectRoots) const QList<QmlDebugObjectReference> &objectRoots)
{ {
QByteArray message; QByteArray message;
QDataStream ds(&message, QIODevice::WriteOnly); QDataStream ds(&message, QIODevice::WriteOnly);
@@ -173,7 +271,7 @@ void DeclarativeToolsClient::setObjectIdList(
QList<int> debugIds; QList<int> debugIds;
QList<QString> objectIds; QList<QString> objectIds;
foreach (const QmlDebug::QmlDebugObjectReference &ref, objectRoots) foreach (const QmlDebugObjectReference &ref, objectRoots)
recurseObjectIdList(ref, debugIds, objectIds); recurseObjectIdList(ref, debugIds, objectIds);
InspectorProtocol::Message cmd = InspectorProtocol::ObjectIdList; InspectorProtocol::Message cmd = InspectorProtocol::ObjectIdList;
@@ -182,7 +280,7 @@ void DeclarativeToolsClient::setObjectIdList(
Q_ASSERT(debugIds.length() == objectIds.length()); 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]; ds << debugIds[i] << objectIds[i];
} }
@@ -423,7 +521,7 @@ void DeclarativeToolsClient::applyChangesFromQmlFile()
} }
void DeclarativeToolsClient::log(LogDirection direction, void DeclarativeToolsClient::log(LogDirection direction,
InspectorProtocol::Message message, int message,
const QString &extra) const QString &extra)
{ {
QString msg; QString msg;
@@ -432,11 +530,14 @@ void DeclarativeToolsClient::log(LogDirection direction,
else else
msg += QLatin1String(" receiving "); msg += QLatin1String(" receiving ");
msg += InspectorProtocol::toString(message); InspectorProtocol::Message msgType
= static_cast<InspectorProtocol::Message>(message);
msg += InspectorProtocol::toString(msgType);
msg += QLatin1Char(' '); msg += QLatin1Char(' ');
msg += extra; msg += extra;
emit logActivity(name(), msg); emit logActivity(name(), msg);
} }
} // namespace Internal } // namespace QmlDebug
} // namespace QmlJSInspector
#include "declarativetoolsclient.moc"

View File

@@ -34,16 +34,13 @@
#include "basetoolsclient.h" #include "basetoolsclient.h"
#include <inspectorprotocol.h> namespace QmlDebug {
namespace QmlJSInspector { class QMLDEBUG_EXPORT DeclarativeToolsClient : public BaseToolsClient
namespace Internal {
class DeclarativeToolsClient : public BaseToolsClient
{ {
Q_OBJECT Q_OBJECT
public: public:
DeclarativeToolsClient(QmlDebug::QmlDebugConnection *client); DeclarativeToolsClient(QmlDebugConnection *client);
void setCurrentObjects(const QList<int> &debugIds); void setCurrentObjects(const QList<int> &debugIds);
void reloadViewer(); void reloadViewer();
@@ -67,7 +64,7 @@ public:
QList<int> currentObjects() const; QList<int> currentObjects() const;
// ### Qt 4.8: remove if we can have access to qdeclarativecontextdata or id's // ### 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(); void clearComponentCache();
@@ -76,15 +73,14 @@ protected:
private: private:
void log(LogDirection direction, void log(LogDirection direction,
QmlJSDebugger::InspectorProtocol::Message message, int message,
const QString &extra = QString()); const QString &extra = QString());
private: private:
QList<int> m_currentDebugIds; QList<int> m_currentDebugIds;
QmlDebug::QmlDebugConnection *m_connection; QmlDebugConnection *m_connection;
}; };
} // namespace Internal } // namespace QmlDebug
} // namespace QmlJSInspector
#endif // DECLARATIVETOOLSCLIENT_H #endif // DECLARATIVETOOLSCLIENT_H

View File

@@ -19,7 +19,10 @@ HEADERS += \
$$PWD/qv8profilerclient.h \ $$PWD/qv8profilerclient.h \
$$PWD/qmldebugconstants.h \ $$PWD/qmldebugconstants.h \
$$PWD/qdebugmessageclient.h \ $$PWD/qdebugmessageclient.h \
$$PWD/qmlenginedebugclient.h $$PWD/qmlenginedebugclient.h \
$$PWD/basetoolsclient.h \
$$PWD/declarativetoolsclient.h \
$$PWD/qmltoolsclient.h
SOURCES += \ SOURCES += \
$$PWD/qmldebugclient.cpp \ $$PWD/qmldebugclient.cpp \
@@ -29,5 +32,8 @@ SOURCES += \
$$PWD/qpacketprotocol.cpp \ $$PWD/qpacketprotocol.cpp \
$$PWD/qv8profilerclient.cpp \ $$PWD/qv8profilerclient.cpp \
$$PWD/qdebugmessageclient.cpp \ $$PWD/qdebugmessageclient.cpp \
$$PWD/qmlenginedebugclient.cpp $$PWD/qmlenginedebugclient.cpp \
$$PWD/basetoolsclient.cpp \
$$PWD/declarativetoolsclient.cpp \
$$PWD/qmltoolsclient.cpp

View File

@@ -20,6 +20,11 @@ QtcLibrary {
files: [ files: [
"baseenginedebugclient.cpp", "baseenginedebugclient.cpp",
"baseenginedebugclient.h", "baseenginedebugclient.h",
"basetoolsclient.cpp",
"basetoolsclient.h",
"declarativeenginedebugclient.h",
"declarativetoolsclient.cpp",
"declarativetoolsclient.h",
"qdebugmessageclient.cpp", "qdebugmessageclient.cpp",
"qdebugmessageclient.h", "qdebugmessageclient.h",
"qmldebugclient.cpp", "qmldebugclient.cpp",
@@ -34,7 +39,6 @@ QtcLibrary {
"qmlprofilertraceclient.h", "qmlprofilertraceclient.h",
"qpacketprotocol.cpp", "qpacketprotocol.cpp",
"qpacketprotocol.h", "qpacketprotocol.h",
"declarativeenginedebugclient.h",
"qmlenginedebugclient.cpp", "qmlenginedebugclient.cpp",
"qmlenginedebugclient.h", "qmlenginedebugclient.h",
"qv8profilerclient.cpp", "qv8profilerclient.cpp",

View File

@@ -30,8 +30,7 @@
**************************************************************************/ **************************************************************************/
#include "qmltoolsclient.h" #include "qmltoolsclient.h"
#include "qmljsclientproxy.h" #include <QStringList>
#include "qmljsinspectorconstants.h"
//INSPECTOR SERVICE PROTOCOL //INSPECTOR SERVICE PROTOCOL
// <HEADER><COMMAND><DATA> // <HEADER><COMMAND><DATA>
@@ -61,11 +60,10 @@ const char DESTROY_OBJECT[] = "destroyObject";
const char MOVE_OBJECT[] = "moveObject"; const char MOVE_OBJECT[] = "moveObject";
const char CLEAR_CACHE[] = "clearCache"; const char CLEAR_CACHE[] = "clearCache";
namespace QmlJSInspector { namespace QmlDebug {
namespace Internal {
QmlToolsClient::QmlToolsClient(QmlDebugConnection *client) QmlToolsClient::QmlToolsClient(QmlDebugConnection *client)
: BaseToolsClient(client, QLatin1String(Constants::QML_INSPECTOR)), : BaseToolsClient(client, QLatin1String("QmlInspector")),
m_connection(client), m_connection(client),
m_requestId(0), m_requestId(0),
m_slowDownFactor(1) m_slowDownFactor(1)
@@ -328,5 +326,4 @@ void QmlToolsClient::log(LogDirection direction,
emit logActivity(name(), msg); emit logActivity(name(), msg);
} }
} // namespace Internal } // namespace QmlDebug
} // namespace QmlJSInspector

View File

@@ -33,14 +33,14 @@
#define QMLTOOLSCLIENT_H #define QMLTOOLSCLIENT_H
#include "basetoolsclient.h" #include "basetoolsclient.h"
namespace QmlJSInspector {
namespace Internal {
class QmlToolsClient : public BaseToolsClient namespace QmlDebug {
class QMLDEBUG_EXPORT QmlToolsClient : public BaseToolsClient
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit QmlToolsClient(QmlDebug::QmlDebugConnection *client); explicit QmlToolsClient(QmlDebugConnection *client);
void setCurrentObjects(const QList<int> &debugIds); void setCurrentObjects(const QList<int> &debugIds);
void reloadViewer(); void reloadViewer();
@@ -64,7 +64,7 @@ public:
QList<int> currentObjects() const; QList<int> currentObjects() const;
// ### Qt 4.8: remove if we can have access to qdeclarativecontextdata or id's // ### 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(); void clearComponentCache();
@@ -78,12 +78,11 @@ private:
private: private:
QList<int> m_currentDebugIds; QList<int> m_currentDebugIds;
QmlDebug::QmlDebugConnection *m_connection; QmlDebugConnection *m_connection;
int m_requestId; int m_requestId;
qreal m_slowDownFactor; qreal m_slowDownFactor;
}; };
} // namespace Internal } // namespace QmlDebug
} // namespace QmlJSInspector
#endif // QMLTOOLSCLIENT_H #endif // QMLTOOLSCLIENT_H

View File

@@ -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=\"Core\" version=\"$$QTCREATOR_VERSION\"/>
<dependency name=\"Find\" version=\"$$QTCREATOR_VERSION\"/> <dependency name=\"Find\" version=\"$$QTCREATOR_VERSION\"/>
<dependency name=\"CppTools\" 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 --> <!-- Debugger plugin adds items to the editor\'s context menu -->
<dependency name=\"CppEditor\" version=\"$$QTCREATOR_VERSION\" type=\"optional\"/> <dependency name=\"CppEditor\" version=\"$$QTCREATOR_VERSION\" type=\"optional\"/>
</dependencyList> </dependencyList>

View File

@@ -74,6 +74,8 @@ CommonOptionsPageWidget::CommonOptionsPageWidget
m_ui.checkBoxSwitchModeOnExit); m_ui.checkBoxSwitchModeOnExit);
m_group->insert(dc->action(RaiseOnInterrupt), m_group->insert(dc->action(RaiseOnInterrupt),
m_ui.checkBoxBringToForegroundOnInterrrupt); m_ui.checkBoxBringToForegroundOnInterrrupt);
m_group->insert(dc->action(ShowQmlObjectTree),
m_ui.checkBoxShowQmlObjectTree);
m_group->insert(dc->action(FontSizeFollowsEditor), m_group->insert(dc->action(FontSizeFollowsEditor),
m_ui.checkBoxFontSizeFollowsEditor); m_ui.checkBoxFontSizeFollowsEditor);
m_group->insert(dc->action(AutoDerefPointers), 0); m_group->insert(dc->action(AutoDerefPointers), 0);
@@ -123,6 +125,7 @@ QString CommonOptionsPageWidget::searchKeyWords() const
<< sep << m_ui.checkBoxSwitchModeOnExit->text() << sep << m_ui.checkBoxSwitchModeOnExit->text()
<< sep << m_ui.labelMaximalStackDepth->text() << sep << m_ui.labelMaximalStackDepth->text()
<< sep << m_ui.checkBoxBringToForegroundOnInterrrupt->text() << sep << m_ui.checkBoxBringToForegroundOnInterrrupt->text()
<< sep << m_ui.checkBoxShowQmlObjectTree->text()
; ;
rc.remove(QLatin1Char('&')); rc.remove(QLatin1Char('&'));
return rc; return rc;

View File

@@ -120,7 +120,14 @@
</item> </item>
</layout> </layout>
</item> </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"> <widget class="QCheckBox" name="checkBoxRegisterForPostMortem">
<property name="toolTip"> <property name="toolTip">
<string>Register Qt Creator for debugging crashed applications.</string> <string>Register Qt Creator for debugging crashed applications.</string>
@@ -130,10 +137,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0"> <item row="3" column="1">
<widget class="QCheckBox" name="checkBoxBringToForegroundOnInterrrupt"> <widget class="QCheckBox" name="checkBoxShowQmlObjectTree">
<property name="toolTip">
<string>Show QML object tree in Locals &amp; Expressions when connected and not stepping.</string>
</property>
<property name="text"> <property name="text">
<string>Bring Qt Creator to foreground when application interrupts</string> <string>Show QML object tree</string>
</property> </property>
</widget> </widget>
</item> </item>

View File

@@ -72,7 +72,8 @@ HEADERS += \
qtmessagelogview.h \ qtmessagelogview.h \
qtmessagelogproxymodel.h \ qtmessagelogproxymodel.h \
qtmessagelogitemdelegate.h \ qtmessagelogitemdelegate.h \
qtmessageloghandler.h qtmessageloghandler.h \
localsandwatcherswindow.h
SOURCES += \ SOURCES += \
basewindow.cpp \ basewindow.cpp \
@@ -123,7 +124,8 @@ SOURCES += \
qtmessagelogview.cpp \ qtmessagelogview.cpp \
qtmessagelogitemdelegate.cpp \ qtmessagelogitemdelegate.cpp \
qtmessageloghandler.cpp \ qtmessageloghandler.cpp \
qtmessagelogeditor.cpp qtmessagelogeditor.cpp \
localsandwatcherswindow.cpp
FORMS += attachexternaldialog.ui \ FORMS += attachexternaldialog.ui \
attachcoredialog.ui \ attachcoredialog.ui \

View File

@@ -8,6 +8,7 @@ QtcPlugin {
Depends { name: "qt"; submodules: ['widgets', 'network', 'script'] } Depends { name: "qt"; submodules: ['widgets', 'network', 'script'] }
Depends { name: "Core" } Depends { name: "Core" }
Depends { name: "CppTools" } Depends { name: "CppTools" }
Depends { name: "QmlJSTools" }
Depends { name: "Find" } Depends { name: "Find" }
Depends { name: "ProjectExplorer" } Depends { name: "ProjectExplorer" }
Depends { name: "TextEditor" } Depends { name: "TextEditor" }
@@ -75,6 +76,8 @@ QtcPlugin {
"disassemblerlines.cpp", "disassemblerlines.cpp",
"disassemblerlines.h", "disassemblerlines.h",
"dumperoptionpage.ui", "dumperoptionpage.ui",
"localsandwatcherswindow.cpp",
"localsandwatcherswindow.h",
"logwindow.cpp", "logwindow.cpp",
"logwindow.h", "logwindow.h",
"memoryagent.cpp", "memoryagent.cpp",
@@ -243,6 +246,12 @@ QtcPlugin {
"qml/qscriptdebuggerclient.cpp", "qml/qscriptdebuggerclient.cpp",
"qml/qmlv8debuggerclient.cpp", "qml/qmlv8debuggerclient.cpp",
"qml/interactiveinterpreter.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.cpp",
"script/scriptengine.h", "script/scriptengine.h",
"shared/backtrace.cpp", "shared/backtrace.cpp",

View File

@@ -36,5 +36,9 @@
<file>images/log.png</file> <file>images/log.png</file>
<file>images/prompt.png</file> <file>images/prompt.png</file>
<file>images/warning.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> </qresource>
</RCC> </RCC>

View File

@@ -3,6 +3,7 @@ include(../../plugins/cpptools/cpptools.pri)
include(../../plugins/find/find.pri) include(../../plugins/find/find.pri)
include(../../plugins/projectexplorer/projectexplorer.pri) include(../../plugins/projectexplorer/projectexplorer.pri)
include(../../plugins/texteditor/texteditor.pri) include(../../plugins/texteditor/texteditor.pri)
include(../../plugins/qmljstools/qmljstools.pri)
include(../../libs/cplusplus/cplusplus.pri) include(../../libs/cplusplus/cplusplus.pri)
include(../../libs/utils/utils.pri) include(../../libs/utils/utils.pri)
include(../../libs/symbianutils/symbianutils.pri) include(../../libs/symbianutils/symbianutils.pri)

View File

@@ -549,6 +549,30 @@ DebuggerSettings::DebuggerSettings(QSettings *settings)
item->setSettingsKey(debugModeGroup, QLatin1String("WatchdogTimeout")); item->setSettingsKey(debugModeGroup, QLatin1String("WatchdogTimeout"));
item->setDefaultValue(20); item->setDefaultValue(20);
insertItem(GdbWatchdogTimeout, item); 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() DebuggerSettings::~DebuggerSettings()

View File

@@ -169,7 +169,12 @@ enum DebuggerActionCode
AlwaysAdjustThreadsColumnWidths, AlwaysAdjustThreadsColumnWidths,
// Modules // Modules
AlwaysAdjustModulesColumnWidths AlwaysAdjustModulesColumnWidths,
// QML Tools
ShowQmlObjectTree,
ShowAppOnTop,
QmlUpdateOnSave
}; };
} // namespace Internal } // namespace Internal

View File

@@ -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_AUTOMATIC_REMOTE[] = "Debugger.Group.Automatic.Remote";
const char G_START_QML[] = "Debugger.Group.Start.Qml"; const char G_START_QML[] = "Debugger.Group.Start.Qml";
// Common actions (accessed by QML inspector) // Common actions
const char INTERRUPT[] = "Debugger.Interrupt"; const char INTERRUPT[] = "Debugger.Interrupt";
const char CONTINUE[] = "Debugger.Continue"; const char CONTINUE[] = "Debugger.Continue";
const char STOP[] = "Debugger.Stop"; const char STOP[] = "Debugger.Stop";
@@ -63,6 +63,8 @@ const char STEPOUT[] = "Debugger.StepOut";
const char NEXT[] = "Debugger.NextLine"; const char NEXT[] = "Debugger.NextLine";
const char REVERSE[] = "Debugger.ReverseDirection"; const char REVERSE[] = "Debugger.ReverseDirection";
const char OPERATE_BY_INSTRUCTION[] = "Debugger.OperateByInstruction"; const char OPERATE_BY_INSTRUCTION[] = "Debugger.OperateByInstruction";
const char QML_SELECTTOOL[] = "Debugger.QmlSelectTool";
const char QML_ZOOMTOOL[] = "Debugger.QmlZoomTool";
// DebuggerMainWindow dock widget names // DebuggerMainWindow dock widget names
const char DOCKWIDGET_BREAK[] = "Debugger.Docks.Break"; const char DOCKWIDGET_BREAK[] = "Debugger.Docks.Break";

View File

@@ -513,6 +513,14 @@ QAbstractItemModel *DebuggerEngine::returnModel() const
return model; 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 *DebuggerEngine::toolTipsModel() const
{ {
QAbstractItemModel *model = watchHandler()->model(TooltipsWatch); QAbstractItemModel *model = watchHandler()->model(TooltipsWatch);

View File

@@ -75,6 +75,7 @@ class SourceFilesHandler;
class ThreadsHandler; class ThreadsHandler;
class WatchHandler; class WatchHandler;
class BreakpointParameters; class BreakpointParameters;
class QmlAdapter;
class QmlCppEngine; class QmlCppEngine;
class DebuggerToolTipContext; class DebuggerToolTipContext;
class MemoryMarkup; class MemoryMarkup;
@@ -231,6 +232,7 @@ public:
virtual QAbstractItemModel *localsModel() const; virtual QAbstractItemModel *localsModel() const;
virtual QAbstractItemModel *watchersModel() const; virtual QAbstractItemModel *watchersModel() const;
virtual QAbstractItemModel *returnModel() const; virtual QAbstractItemModel *returnModel() const;
virtual QAbstractItemModel *inspectorModel() const;
virtual QAbstractItemModel *toolTipsModel() const; virtual QAbstractItemModel *toolTipsModel() const;
virtual QAbstractItemModel *sourceFilesModel() const; virtual QAbstractItemModel *sourceFilesModel() const;
virtual QAbstractItemModel *qtMessageLogModel() const; virtual QAbstractItemModel *qtMessageLogModel() const;
@@ -408,7 +410,7 @@ private:
// Wrapper engine needs access to state of its subengines. // Wrapper engine needs access to state of its subengines.
friend class Internal::QmlCppEngine; friend class Internal::QmlCppEngine;
friend class Internal::DebuggerPluginPrivate; friend class Internal::DebuggerPluginPrivate;
friend class QmlAdapter; friend class Internal::QmlAdapter;
virtual void setState(DebuggerState state, bool forced = false); virtual void setState(DebuggerState state, bool forced = false);

View File

@@ -62,6 +62,7 @@
#include "watchwindow.h" #include "watchwindow.h"
#include "watchutils.h" #include "watchutils.h"
#include "debuggertooltipmanager.h" #include "debuggertooltipmanager.h"
#include "localsandwatcherswindow.h"
#include "snapshothandler.h" #include "snapshothandler.h"
#include "threadshandler.h" #include "threadshandler.h"
@@ -1119,6 +1120,10 @@ public slots:
void attachedToProcess(const QString &channel, const QString &sysroot, void attachedToProcess(const QString &channel, const QString &sysroot,
const QString &remoteCommandLine, const QString &remoteExecutable); const QString &remoteCommandLine, const QString &remoteExecutable);
void updateQmlActions() {
action(QmlUpdateOnSave)->setEnabled(boolSetting(ShowQmlObjectTree));
}
public: public:
DebuggerMainWindow *m_mainWindow; DebuggerMainWindow *m_mainWindow;
DebuggerRunControlFactory *m_debuggerRunControlFactory; DebuggerRunControlFactory *m_debuggerRunControlFactory;
@@ -1177,6 +1182,7 @@ public:
WatchWindow *m_returnWindow; WatchWindow *m_returnWindow;
WatchWindow *m_localsWindow; WatchWindow *m_localsWindow;
WatchWindow *m_watchersWindow; WatchWindow *m_watchersWindow;
WatchWindow *m_inspectorWindow;
BaseWindow *m_registerWindow; BaseWindow *m_registerWindow;
BaseWindow *m_modulesWindow; BaseWindow *m_modulesWindow;
BaseWindow *m_snapshotWindow; BaseWindow *m_snapshotWindow;
@@ -1184,6 +1190,7 @@ public:
BaseWindow *m_stackWindow; BaseWindow *m_stackWindow;
BaseWindow *m_threadsWindow; BaseWindow *m_threadsWindow;
LogWindow *m_logWindow; LogWindow *m_logWindow;
LocalsAndWatchersWindow *m_localsAndWatchersWindow;
bool m_busy; bool m_busy;
QString m_lastPermanentStatusMessage; QString m_lastPermanentStatusMessage;
@@ -1230,6 +1237,7 @@ DebuggerPluginPrivate::DebuggerPluginPrivate(DebuggerPlugin *plugin) :
m_returnWindow = 0; m_returnWindow = 0;
m_localsWindow = 0; m_localsWindow = 0;
m_watchersWindow = 0; m_watchersWindow = 0;
m_inspectorWindow = 0;
m_registerWindow = 0; m_registerWindow = 0;
m_modulesWindow = 0; m_modulesWindow = 0;
m_snapshotWindow = 0; m_snapshotWindow = 0;
@@ -1237,6 +1245,7 @@ DebuggerPluginPrivate::DebuggerPluginPrivate(DebuggerPlugin *plugin) :
m_stackWindow = 0; m_stackWindow = 0;
m_threadsWindow = 0; m_threadsWindow = 0;
m_logWindow = 0; m_logWindow = 0;
m_localsAndWatchersWindow = 0;
m_qtMessageLogWindow = 0; m_qtMessageLogWindow = 0;
m_mainWindow = 0; m_mainWindow = 0;
@@ -2130,6 +2139,7 @@ void DebuggerPluginPrivate::connectEngine(DebuggerEngine *engine)
//m_threadBox->setModel(engine->threadsModel()); //m_threadBox->setModel(engine->threadsModel());
//m_threadBox->setModelColumn(ThreadData::ComboNameColumn); //m_threadBox->setModelColumn(ThreadData::ComboNameColumn);
m_watchersWindow->setModel(engine->watchersModel()); m_watchersWindow->setModel(engine->watchersModel());
m_inspectorWindow->setModel(engine->inspectorModel());
m_qtMessageLogWindow->setModel(engine->qtMessageLogModel()); m_qtMessageLogWindow->setModel(engine->qtMessageLogModel());
engine->watchHandler()->rebuildModel(); engine->watchHandler()->rebuildModel();
@@ -2162,6 +2172,7 @@ void DebuggerPluginPrivate::fontSettingsChanged
changeFontSize(m_stackWindow, size); changeFontSize(m_stackWindow, size);
changeFontSize(m_threadsWindow, size); changeFontSize(m_threadsWindow, size);
changeFontSize(m_watchersWindow, size); changeFontSize(m_watchersWindow, size);
changeFontSize(m_inspectorWindow, size);
} }
void DebuggerPluginPrivate::cleanupViews() void DebuggerPluginPrivate::cleanupViews()
@@ -2261,7 +2272,7 @@ void DebuggerPluginPrivate::updateWatchersWindow()
m_watchersWindow->setVisible( m_watchersWindow->setVisible(
m_watchersWindow->model()->rowCount(QModelIndex()) > 0); m_watchersWindow->model()->rowCount(QModelIndex()) > 0);
m_returnWindow->setVisible( m_returnWindow->setVisible(
m_returnWindow->model()->rowCount(QModelIndex()) > 0); m_returnWindow->model()->rowCount(QModelIndex()) > 0);
} }
void DebuggerPluginPrivate::updateState(DebuggerEngine *engine) void DebuggerPluginPrivate::updateState(DebuggerEngine *engine)
@@ -2305,6 +2316,7 @@ void DebuggerPluginPrivate::updateState(DebuggerEngine *engine)
m_debugWithoutDeployAction->setEnabled(false); m_debugWithoutDeployAction->setEnabled(false);
m_visibleStartAction->setAction(m_continueAction); m_visibleStartAction->setAction(m_continueAction);
m_hiddenStopAction->setAction(m_exitAction); m_hiddenStopAction->setAction(m_exitAction);
m_localsAndWatchersWindow->setShowLocals(true);
} else if (state == InferiorRunOk) { } else if (state == InferiorRunOk) {
// Shift-F5 interrupts. It is also "interruptible". // Shift-F5 interrupts. It is also "interruptible".
m_interruptAction->setEnabled(true); m_interruptAction->setEnabled(true);
@@ -2314,6 +2326,7 @@ void DebuggerPluginPrivate::updateState(DebuggerEngine *engine)
m_debugWithoutDeployAction->setEnabled(false); m_debugWithoutDeployAction->setEnabled(false);
m_visibleStartAction->setAction(m_interruptAction); m_visibleStartAction->setAction(m_interruptAction);
m_hiddenStopAction->setAction(m_interruptAction); m_hiddenStopAction->setAction(m_interruptAction);
m_localsAndWatchersWindow->setShowLocals(false);
} else if (state == DebuggerFinished) { } else if (state == DebuggerFinished) {
// We don't want to do anything anymore. // We don't want to do anything anymore.
m_interruptAction->setEnabled(false); m_interruptAction->setEnabled(false);
@@ -2403,7 +2416,6 @@ void DebuggerPluginPrivate::updateState(DebuggerEngine *engine)
|| state == DebuggerFinished || state == DebuggerFinished
|| state == InferiorUnrunnable; || state == InferiorUnrunnable;
setBusyCursor(!notbusy); setBusyCursor(!notbusy);
} }
void DebuggerPluginPrivate::updateDebugActions() void DebuggerPluginPrivate::updateDebugActions()
@@ -2927,6 +2939,8 @@ void DebuggerPluginPrivate::extensionsInitialized()
m_localsWindow->setObjectName(QLatin1String("CppDebugLocals")); m_localsWindow->setObjectName(QLatin1String("CppDebugLocals"));
m_watchersWindow = new WatchWindow(WatchTreeView::WatchersType); m_watchersWindow = new WatchWindow(WatchTreeView::WatchersType);
m_watchersWindow->setObjectName(QLatin1String("CppDebugWatchers")); m_watchersWindow->setObjectName(QLatin1String("CppDebugWatchers"));
m_inspectorWindow = new WatchWindow(WatchTreeView::InspectType);
m_inspectorWindow->setObjectName(QLatin1String("Inspector"));
// Snapshot // Snapshot
m_snapshotHandler = new SnapshotHandler; m_snapshotHandler = new SnapshotHandler;
@@ -3018,6 +3032,22 @@ void DebuggerPluginPrivate::extensionsInitialized()
connect(action(OperateByInstruction), SIGNAL(triggered(bool)), connect(action(OperateByInstruction), SIGNAL(triggered(bool)),
SLOT(handleOperateByInstructionTriggered(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 = ActionContainer *debugMenu =
am->actionContainer(ProjectExplorer::Constants::M_DEBUG); am->actionContainer(ProjectExplorer::Constants::M_DEBUG);
@@ -3044,17 +3074,13 @@ void DebuggerPluginPrivate::extensionsInitialized()
m_mainWindow->createDockWidget(CppLanguage, m_stackWindow); m_mainWindow->createDockWidget(CppLanguage, m_stackWindow);
m_mainWindow->createDockWidget(CppLanguage, m_threadsWindow); m_mainWindow->createDockWidget(CppLanguage, m_threadsWindow);
QSplitter *localsAndWatchers = new MiniSplitter(Qt::Vertical); m_localsAndWatchersWindow = new LocalsAndWatchersWindow(
localsAndWatchers->setObjectName(QLatin1String(DOCKWIDGET_WATCHERS)); m_localsWindow, m_inspectorWindow, m_returnWindow,
localsAndWatchers->setWindowTitle(m_localsWindow->windowTitle()); m_watchersWindow);
localsAndWatchers->addWidget(m_localsWindow); m_localsAndWatchersWindow->setObjectName(QLatin1String(DOCKWIDGET_WATCHERS));
localsAndWatchers->addWidget(m_returnWindow); m_localsAndWatchersWindow->setWindowTitle(m_localsWindow->windowTitle());
localsAndWatchers->addWidget(m_watchersWindow);
localsAndWatchers->setStretchFactor(0, 3);
localsAndWatchers->setStretchFactor(1, 1);
localsAndWatchers->setStretchFactor(2, 1);
dock = m_mainWindow->createDockWidget(CppLanguage, localsAndWatchers); dock = m_mainWindow->createDockWidget(CppLanguage, m_localsAndWatchersWindow);
dock->setProperty(DOCKWIDGET_DEFAULT_AREA, Qt::RightDockWidgetArea); dock->setProperty(DOCKWIDGET_DEFAULT_AREA, Qt::RightDockWidgetArea);
m_mainWindow->addStagedMenuEntries(); m_mainWindow->addStagedMenuEntries();
@@ -3443,6 +3469,11 @@ void DebuggerPluginPrivate::extensionsInitialized()
connect(action(SettingsDialog), SIGNAL(triggered()), connect(action(SettingsDialog), SIGNAL(triggered()),
SLOT(showSettingsDialog())); SLOT(showSettingsDialog()));
// QML Actions
connect(action(ShowQmlObjectTree), SIGNAL(valueChanged(QVariant)),
SLOT(updateQmlActions()));
updateQmlActions();
// Toolbar // Toolbar
QWidget *toolbarContainer = new QWidget; QWidget *toolbarContainer = new QWidget;
@@ -3472,6 +3503,19 @@ void DebuggerPluginPrivate::extensionsInitialized()
hbox->addSpacerItem(new QSpacerItem(4, 0)); hbox->addSpacerItem(new QSpacerItem(4, 0));
m_mainWindow->setToolBar(CppLanguage, toolbarContainer); 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); m_mainWindow->setToolBar(AnyLanguage, m_statusLabel);
connect(action(EnableReverseDebugging), connect(action(EnableReverseDebugging),

View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View File

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

View 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

View 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

View File

@@ -8,7 +8,10 @@ HEADERS += \
$$PWD/qscriptdebuggerclient.h \ $$PWD/qscriptdebuggerclient.h \
$$PWD/qmlv8debuggerclient.h \ $$PWD/qmlv8debuggerclient.h \
$$PWD/interactiveinterpreter.h \ $$PWD/interactiveinterpreter.h \
$$PWD/qmlv8debuggerclientconstants.h $$PWD/qmlv8debuggerclientconstants.h \
$$PWD/qmlinspectoragent.h \
$$PWD/qmllivetextpreview.h \
$$PWD/qmlinspectoradapter.h
SOURCES += \ SOURCES += \
$$PWD/qmlengine.cpp \ $$PWD/qmlengine.cpp \
@@ -17,4 +20,7 @@ SOURCES += \
$$PWD/qmlcppengine.cpp \ $$PWD/qmlcppengine.cpp \
$$PWD/qscriptdebuggerclient.cpp \ $$PWD/qscriptdebuggerclient.cpp \
$$PWD/qmlv8debuggerclient.cpp \ $$PWD/qmlv8debuggerclient.cpp \
$$PWD/interactiveinterpreter.cpp $$PWD/interactiveinterpreter.cpp \
$$PWD/qmlinspectoragent.cpp \
$$PWD/qmllivetextpreview.cpp \
$$PWD/qmlinspectoradapter.cpp

View File

@@ -32,116 +32,80 @@
#include "qmladapter.h" #include "qmladapter.h"
#include "qscriptdebuggerclient.h"
#include "qmlv8debuggerclient.h"
#include "qmlengine.h" #include "qmlengine.h"
#include "qmlv8debuggerclient.h"
#include "qscriptdebuggerclient.h"
#include <extensionsystem/pluginmanager.h> #include <qmldebug/qdebugmessageclient.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <qmldebug/baseenginedebugclient.h>
#include <qmldebug/qdebugmessageclient.h>
#include <QTimer>
#include <QDebug> #include <QDebug>
#include <QWeakPointer>
namespace Debugger { namespace Debugger {
namespace Internal { 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) 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())); m_connectionTimer.setInterval(4000);
d->m_conn = new QmlDebugConnection(this); m_connectionTimer.setSingleShot(true);
connect(d->m_conn, SIGNAL(stateChanged(QAbstractSocket::SocketState)), connect(&m_connectionTimer, SIGNAL(timeout()), SLOT(checkConnectionState()));
m_conn = new QmlDebugConnection(this);
connect(m_conn, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
SLOT(connectionStateChanged())); SLOT(connectionStateChanged()));
connect(d->m_conn, SIGNAL(error(QAbstractSocket::SocketError)), connect(m_conn, SIGNAL(error(QAbstractSocket::SocketError)),
SLOT(connectionErrorOccurred(QAbstractSocket::SocketError))); SLOT(connectionErrorOccurred(QAbstractSocket::SocketError)));
ExtensionSystem::PluginManager *pluginManager =
ExtensionSystem::PluginManager::instance();
pluginManager->addObject(this);
createDebuggerClients(); createDebuggerClients();
d->m_msgClient = new QDebugMessageClient(d->m_conn); m_msgClient = new QDebugMessageClient(m_conn);
connect(d->m_msgClient, SIGNAL(newStatus(QmlDebugClient::Status)), connect(m_msgClient, SIGNAL(newStatus(QmlDebugClient::Status)),
this, SLOT(clientStatusChanged(QmlDebugClient::Status))); this, SLOT(clientStatusChanged(QmlDebugClient::Status)));
} }
QmlAdapter::~QmlAdapter() 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) void QmlAdapter::beginConnectionTcp(const QString &address, quint16 port)
{ {
if (d->m_engine.isNull() if (m_engine.isNull()
|| (d->m_conn && d->m_conn->state() != QAbstractSocket::UnconnectedState)) || (m_conn && m_conn->state() != QAbstractSocket::UnconnectedState))
return; return;
showConnectionStatusMessage(tr("Connecting to debug server %1:%2").arg(address).arg( showConnectionStatusMessage(tr("Connecting to debug server %1:%2").arg(address).arg(
QString::number(port))); QString::number(port)));
d->m_conn->connectToHost(address, port); m_conn->connectToHost(address, port);
//A timeout to check the connection state //A timeout to check the connection state
d->m_connectionTimer.start(); m_connectionTimer.start();
} }
void QmlAdapter::beginConnectionOst(const QString &channel) void QmlAdapter::beginConnectionOst(const QString &channel)
{ {
if (d->m_engine.isNull() if (m_engine.isNull()
|| (d->m_conn && d->m_conn->state() != QAbstractSocket::UnconnectedState)) || (m_conn && m_conn->state() != QAbstractSocket::UnconnectedState))
return; return;
showConnectionStatusMessage(tr("Connecting to debug server on %1").arg(channel)); 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 //A timeout to check the connection state
d->m_connectionTimer.start(); m_connectionTimer.start();
} }
void QmlAdapter::closeConnection() void QmlAdapter::closeConnection()
{ {
if (d->m_connectionTimer.isActive()) { if (m_connectionTimer.isActive()) {
d->m_connectionTimer.stop(); m_connectionTimer.stop();
} else { } else {
if (d->m_conn) { if (m_conn) {
d->m_conn->close(); m_conn->close();
} }
} }
} }
@@ -149,13 +113,13 @@ void QmlAdapter::closeConnection()
void QmlAdapter::connectionErrorOccurred(QAbstractSocket::SocketError socketError) void QmlAdapter::connectionErrorOccurred(QAbstractSocket::SocketError socketError)
{ {
showConnectionStatusMessage(tr("Error: (%1) %2", "%1=error code, %2=error message") 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. // this is only an error if we are already connected and something goes wrong.
if (isConnected()) { if (isConnected()) {
emit connectionError(socketError); emit connectionError(socketError);
} else { } else {
d->m_connectionTimer.stop(); m_connectionTimer.stop();
emit connectionStartupFailed(); emit connectionStartupFailed();
} }
} }
@@ -179,13 +143,13 @@ void QmlAdapter::debugClientStatusChanged(QmlDebugClient::Status status)
QmlDebugClient *client = qobject_cast<QmlDebugClient*>(sender()); QmlDebugClient *client = qobject_cast<QmlDebugClient*>(sender());
QTC_ASSERT(client, return); QTC_ASSERT(client, return);
d->m_qmlClient = qobject_cast<Internal::BaseQmlDebuggerClient *>(client); m_qmlClient = qobject_cast<Internal::BaseQmlDebuggerClient *>(client);
d->m_qmlClient->startSession(); m_qmlClient->startSession();
} }
void QmlAdapter::connectionStateChanged() void QmlAdapter::connectionStateChanged()
{ {
switch (d->m_conn->state()) { switch (m_conn->state()) {
case QAbstractSocket::UnconnectedState: case QAbstractSocket::UnconnectedState:
{ {
showConnectionStatusMessage(tr("disconnected.\n\n")); showConnectionStatusMessage(tr("disconnected.\n\n"));
@@ -203,7 +167,7 @@ void QmlAdapter::connectionStateChanged()
{ {
showConnectionStatusMessage(tr("connected.\n")); showConnectionStatusMessage(tr("connected.\n"));
d->m_connectionTimer.stop(); m_connectionTimer.stop();
//reloadEngines(); //reloadEngines();
emit connected(); emit connected();
@@ -228,125 +192,83 @@ void QmlAdapter::checkConnectionState()
void QmlAdapter::createDebuggerClients() void QmlAdapter::createDebuggerClients()
{ {
Internal::QScriptDebuggerClient *debugClient1 = new Internal::QScriptDebuggerClient(m_conn);
Internal::QScriptDebuggerClient *client1 = new Internal::QScriptDebuggerClient(d->m_conn); connect(debugClient1, SIGNAL(newStatus(QmlDebugClient::Status)),
connect(client1, SIGNAL(newStatus(QmlDebugClient::Status)),
this, SLOT(clientStatusChanged(QmlDebugClient::Status))); this, SLOT(clientStatusChanged(QmlDebugClient::Status)));
connect(client1, SIGNAL(newStatus(QmlDebugClient::Status)), connect(debugClient1, SIGNAL(newStatus(QmlDebugClient::Status)),
this, SLOT(debugClientStatusChanged(QmlDebugClient::Status))); this, SLOT(debugClientStatusChanged(QmlDebugClient::Status)));
Internal::QmlV8DebuggerClient *client2 = new Internal::QmlV8DebuggerClient(d->m_conn); Internal::QmlV8DebuggerClient *debugClient2 = new Internal::QmlV8DebuggerClient(m_conn);
connect(client2, SIGNAL(newStatus(QmlDebugClient::Status)), connect(debugClient2, SIGNAL(newStatus(QmlDebugClient::Status)),
this, SLOT(clientStatusChanged(QmlDebugClient::Status))); this, SLOT(clientStatusChanged(QmlDebugClient::Status)));
connect(client2, SIGNAL(newStatus(QmlDebugClient::Status)), connect(debugClient2, SIGNAL(newStatus(QmlDebugClient::Status)),
this, SLOT(debugClientStatusChanged(QmlDebugClient::Status))); this, SLOT(debugClientStatusChanged(QmlDebugClient::Status)));
d->debugClients.insert(client1->name(),client1); m_debugClients.insert(debugClient1->name(),debugClient1);
d->debugClients.insert(client2->name(),client2); m_debugClients.insert(debugClient2->name(),debugClient2);
debugClient1->setEngine((Internal::QmlEngine*)(m_engine.data()));
client1->setEngine((Internal::QmlEngine*)(d->m_engine.data())); debugClient2->setEngine((Internal::QmlEngine*)(m_engine.data()));
client2->setEngine((Internal::QmlEngine*)(d->m_engine.data()));
//engine->startSuccessful(); // FIXME: AAA: port to new debugger states
} }
bool QmlAdapter::isConnected() const 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 QmlDebugConnection *QmlAdapter::connection() const
{ {
return d->m_conn; return m_conn;
} }
DebuggerEngine *QmlAdapter::debuggerEngine() const DebuggerEngine *QmlAdapter::debuggerEngine() const
{ {
return d->m_engine.data(); return m_engine.data();
} }
void QmlAdapter::showConnectionStatusMessage(const QString &message) void QmlAdapter::showConnectionStatusMessage(const QString &message)
{ {
if (!d->m_engine.isNull()) if (!m_engine.isNull())
d->m_engine.data()->showMessage(QLatin1String("QML Debugger: ") + message, LogStatus); m_engine.data()->showMessage(QLatin1String("QML Debugger: ") + message, LogStatus);
} }
void QmlAdapter::showConnectionErrorMessage(const QString &message) void QmlAdapter::showConnectionErrorMessage(const QString &message)
{ {
if (!d->m_engine.isNull()) if (!m_engine.isNull())
d->m_engine.data()->showMessage(QLatin1String("QML Debugger: ") + message, LogError); m_engine.data()->showMessage(QLatin1String("QML Debugger: ") + message, LogError);
} }
bool QmlAdapter::disableJsDebugging(bool block) bool QmlAdapter::disableJsDebugging(bool block)
{ {
if (d->m_engine.isNull()) if (m_engine.isNull())
return block; return block;
bool isBlocked = d->m_engine.data()->state() == InferiorRunOk; bool isBlocked = m_engine.data()->state() == InferiorRunOk;
if (isBlocked == block) if (isBlocked == block)
return block; return block;
if (block) { if (block)
d->m_engine.data()->continueInferior(); m_engine.data()->continueInferior();
} else { else
d->m_engine.data()->requestInterruptInferior(); m_engine.data()->requestInterruptInferior();
}
return isBlocked; return isBlocked;
} }
Internal::BaseQmlDebuggerClient *QmlAdapter::activeDebuggerClient() Internal::BaseQmlDebuggerClient *QmlAdapter::activeDebuggerClient()
{ {
return d->m_qmlClient; return m_qmlClient;
} }
QHash<QString, Internal::BaseQmlDebuggerClient*> QmlAdapter::debuggerClients() QHash<QString, Internal::BaseQmlDebuggerClient*> QmlAdapter::debuggerClients()
{ {
return d->debugClients; return m_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)));
} }
QDebugMessageClient *QmlAdapter::messageClient() const QDebugMessageClient *QmlAdapter::messageClient() const
{ {
return d->m_msgClient; return 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();
} }
void QmlAdapter::logServiceStatusChange(const QString &service, float version, 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) void QmlAdapter::logServiceActivity(const QString &service, const QString &logMessage)
{ {
if (!d->m_engine.isNull()) if (!m_engine.isNull())
d->m_engine.data()->showMessage(service + QLatin1Char(' ') + logMessage, LogDebug); m_engine.data()->showMessage(service + QLatin1Char(' ') + logMessage, LogDebug);
} }
} // namespace Internal
} // namespace Debugger } // namespace Debugger

View File

@@ -35,18 +35,21 @@
#include "debugger_global.h" #include "debugger_global.h"
#include <QObject>
#include <QAbstractSocket>
#include <qmldebug/qmldebugclient.h> #include <qmldebug/qmldebugclient.h>
#include <QAbstractSocket>
#include <QObject>
#include <QPointer>
#include <QTimer>
using namespace QmlDebug;
namespace QmlDebug { namespace QmlDebug {
class BaseEngineDebugClient; class BaseEngineDebugClient;
class QmlDebugConnection; class QmlDebugConnection;
class QDebugMessageClient; class QDebugMessageClient;
} }
using namespace QmlDebug;
namespace Debugger { namespace Debugger {
class DebuggerEngine; class DebuggerEngine;
@@ -54,9 +57,8 @@ class DebuggerEngine;
namespace Internal { namespace Internal {
class BaseQmlDebuggerClient; class BaseQmlDebuggerClient;
class QmlAdapterPrivate; class QmlAdapterPrivate;
} // namespace Internal
class DEBUGGER_EXPORT QmlAdapter : public QObject class QmlAdapter : public QObject
{ {
Q_OBJECT Q_OBJECT
@@ -79,14 +81,8 @@ public:
QHash<QString, Internal::BaseQmlDebuggerClient*> debuggerClients(); QHash<QString, Internal::BaseQmlDebuggerClient*> debuggerClients();
BaseEngineDebugClient *engineDebugClient() const; BaseEngineDebugClient *engineDebugClient() const;
void setEngineDebugClient(BaseEngineDebugClient *client);
QDebugMessageClient *messageClient() const; QDebugMessageClient *messageClient() const;
int currentSelectedDebugId() const;
QString currentSelectedDisplayName() const;
void setCurrentSelectedDebugInfo(int debugId, const QString &displayName = QString());
public slots: public slots:
void logServiceStatusChange(const QString &service, float version, void logServiceStatusChange(const QString &service, float version,
QmlDebugClient::Status newStatus); QmlDebugClient::Status newStatus);
@@ -98,7 +94,6 @@ signals:
void connectionStartupFailed(); void connectionStartupFailed();
void connectionError(QAbstractSocket::SocketError socketError); void connectionError(QAbstractSocket::SocketError socketError);
void serviceConnectionError(const QString serviceName); void serviceConnectionError(const QString serviceName);
void selectionChanged();
private slots: private slots:
void connectionErrorOccurred(QAbstractSocket::SocketError socketError); void connectionErrorOccurred(QAbstractSocket::SocketError socketError);
@@ -113,9 +108,15 @@ private:
void showConnectionErrorMessage(const QString &message); void showConnectionErrorMessage(const QString &message);
private: 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 } // namespace Debugger
#endif // QMLADAPTER_H #endif // QMLADAPTER_H

View File

@@ -37,6 +37,7 @@
#include "stackhandler.h" #include "stackhandler.h"
#include "qmlengine.h" #include "qmlengine.h"
#include "qtmessageloghandler.h" #include "qtmessageloghandler.h"
#include "watchdata.h"
#include <coreplugin/icore.h> #include <coreplugin/icore.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
@@ -149,6 +150,8 @@ bool QmlCppEngine::setToolTipExpression(const QPoint & mousePos,
void QmlCppEngine::updateWatchData(const WatchData &data, void QmlCppEngine::updateWatchData(const WatchData &data,
const WatchUpdateFlags &flags) const WatchUpdateFlags &flags)
{ {
if (data.iname.startsWith("inspect."))
d->m_qmlEngine->updateWatchData(data, flags);
d->m_activeEngine->updateWatchData(data, flags); d->m_activeEngine->updateWatchData(data, flags);
} }

View File

@@ -40,7 +40,7 @@ namespace Internal {
class QmlCppEnginePrivate; class QmlCppEnginePrivate;
class DEBUGGER_EXPORT QmlCppEngine : public DebuggerEngine class QmlCppEngine : public DebuggerEngine
{ {
Q_OBJECT Q_OBJECT

View File

@@ -32,8 +32,10 @@
#include "qmlengine.h" #include "qmlengine.h"
#include "qmladapter.h" #include "qmladapter.h"
#include "qmlinspectoradapter.h"
#include "interactiveinterpreter.h" #include "interactiveinterpreter.h"
#include "baseqmldebuggerclient.h" #include "baseqmldebuggerclient.h"
#include "qmlinspectoragent.h"
#include "debuggerstartparameters.h" #include "debuggerstartparameters.h"
#include "debuggeractions.h" #include "debuggeractions.h"
@@ -113,13 +115,13 @@ public:
private: private:
friend class QmlEngine; friend class QmlEngine;
QmlAdapter m_adapter; QmlAdapter m_adapter;
QmlInspectorAdapter m_inspectorAdapter;
ApplicationLauncher m_applicationLauncher; ApplicationLauncher m_applicationLauncher;
QTimer m_noDebugOutputTimer; QTimer m_noDebugOutputTimer;
QmlOutputParser m_outputParser; QmlOutputParser m_outputParser;
QHash<QString, QTextDocument*> m_sourceDocuments; QHash<QString, QTextDocument*> m_sourceDocuments;
QHash<QString, QWeakPointer<TextEditor::ITextEditor> > m_sourceEditors; QHash<QString, QWeakPointer<TextEditor::ITextEditor> > m_sourceEditors;
InteractiveInterpreter m_interpreter; InteractiveInterpreter m_interpreter;
bool m_validContext;
QHash<QString,BreakpointModelId> pendingBreakpoints; QHash<QString,BreakpointModelId> pendingBreakpoints;
QList<quint32> queryIds; QList<quint32> queryIds;
bool m_retryOnConnectFail; bool m_retryOnConnectFail;
@@ -128,10 +130,11 @@ private:
QmlEnginePrivate::QmlEnginePrivate(QmlEngine *q) QmlEnginePrivate::QmlEnginePrivate(QmlEngine *q)
: m_adapter(q), : m_adapter(q),
m_validContext(false), m_inspectorAdapter(&m_adapter, q),
m_retryOnConnectFail(false), m_retryOnConnectFail(false),
m_automaticConnect(false) m_automaticConnect(false)
{} {
}
class ASTWalker: public Visitor class ASTWalker: public Visitor
{ {
@@ -326,14 +329,18 @@ QmlEngine::QmlEngine(const DebuggerStartParameters &startParameters,
SLOT(updateCurrentContext())); SLOT(updateCurrentContext()));
connect(this->stackHandler(), SIGNAL(currentIndexChanged()), connect(this->stackHandler(), SIGNAL(currentIndexChanged()),
SLOT(updateCurrentContext())); SLOT(updateCurrentContext()));
connect(&d->m_adapter, SIGNAL(selectionChanged()), connect(&d->m_inspectorAdapter, SIGNAL(selectionChanged()),
SLOT(updateCurrentContext())); SLOT(updateCurrentContext()));
connect(d->m_inspectorAdapter.agent(), SIGNAL(
expressionResult(quint32,QVariant)),
SLOT(expressionEvaluated(quint32,QVariant)));
connect(d->m_adapter.messageClient(), connect(d->m_adapter.messageClient(),
SIGNAL(message(QtMsgType,QString, SIGNAL(message(QtMsgType,QString,
QmlDebug::QDebugContextInfo)), QmlDebug::QDebugContextInfo)),
SLOT(appendDebugOutput(QtMsgType,QString, SLOT(appendDebugOutput(QtMsgType,QString,
QmlDebug::QDebugContextInfo))); QmlDebug::QDebugContextInfo)));
connect(&d->m_applicationLauncher, connect(&d->m_applicationLauncher,
SIGNAL(processExited(int)), SIGNAL(processExited(int)),
SLOT(disconnected())); SLOT(disconnected()));
@@ -1027,19 +1034,23 @@ void QmlEngine::updateWatchData(const WatchData &data,
{ {
// qDebug() << "UPDATE WATCH DATA" << data.toString(); // qDebug() << "UPDATE WATCH DATA" << data.toString();
//watchHandler()->rebuildModel(); //watchHandler()->rebuildModel();
showStatusMessage(tr("Stopped."), 5000); //showStatusMessage(tr("Stopped."), 5000);
if (!data.name.isEmpty() && d->m_adapter.activeDebuggerClient()) { if (data.iname.startsWith("inspect.")) {
if (data.isValueNeeded()) { d->m_inspectorAdapter.agent()->updateWatchData(data);
d->m_adapter.activeDebuggerClient()->updateWatchData(data); } else {
} if (!data.name.isEmpty() && d->m_adapter.activeDebuggerClient()) {
if (data.isChildrenNeeded() if (data.isValueNeeded()) {
&& watchHandler()->isExpandedIName(data.iname)) { d->m_adapter.activeDebuggerClient()->updateWatchData(data);
d->m_adapter.activeDebuggerClient()->expandObject(data.iname, data.id); }
if (data.isChildrenNeeded()
&& watchHandler()->isExpandedIName(data.iname)) {
d->m_adapter.activeDebuggerClient()->expandObject(data.iname, data.id);
}
} }
synchronizeWatchers();
} }
synchronizeWatchers();
if (!data.isSomethingNeeded()) if (!data.isSomethingNeeded())
watchHandler()->insertData(data); watchHandler()->insertData(data);
@@ -1111,8 +1122,7 @@ void QmlEngine::updateCurrentContext()
{ {
const QString context = state() == InferiorStopOk ? const QString context = state() == InferiorStopOk ?
stackHandler()->currentFrame().function : stackHandler()->currentFrame().function :
d->m_adapter.currentSelectedDisplayName(); d->m_inspectorAdapter.currentSelectedDisplayName();
d->m_validContext = !context.isEmpty();
showMessage(tr("Context: ").append(context), QtMessageLogStatus); 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; bool didEvaluate = true;
//Check if string is only white spaces //Check if string is only white spaces
if (!expression.trimmed().isEmpty()) { if (!expression.trimmed().isEmpty()) {
//Check for a valid context //check if it can be evaluated
if (d->m_validContext) { if (canEvaluateScript(expression)) {
//check if it can be evaluated //Evaluate expression based on engine state
if (canEvaluateScript(expression)) { //When engine->state() == InferiorStopOk, the expression
//Evaluate expression based on engine state //is sent to V8DebugService. In all other cases, the
//When engine->state() == InferiorStopOk, the expression //expression is evaluated by QDeclarativeEngine.
//is sent to V8DebugService. In all other cases, the if (state() != InferiorStopOk) {
//expression is evaluated by QDeclarativeEngine. QmlInspectorAgent *agent = d->m_inspectorAdapter.agent();
if (state() != InferiorStopOk) { quint32 queryId
BaseEngineDebugClient *engineDebug = = agent->queryExpressionResult(
d->m_adapter.engineDebugClient(); d->m_inspectorAdapter.currentSelectedDebugId(),
expression);
int id = d->m_adapter.currentSelectedDebugId(); if (queryId) {
if (engineDebug && id != -1) { d->queryIds << queryId;
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.")));
}
}
} else { } else {
executeDebuggerCommand(expression, QmlLanguage); didEvaluate = false;
qtMessageLogHandler()->
appendItem(
new QtMessageLogItem(
qtMessageLogHandler()->root(),
QtMessageLogHandler::ErrorType,
_("Error evaluating expression.")));
} }
} else { } else {
didEvaluate = false; executeDebuggerCommand(expression, QmlLanguage);
} }
} else { } else {
//Incase of invalid context, show Error message didEvaluate = false;
qtMessageLogHandler()->
appendItem(new QtMessageLogItem(
qtMessageLogHandler()->root(),
QtMessageLogHandler::ErrorType,
_("Cannot evaluate without "
"a valid QML/JS Context.")),
qtMessageLogHandler()->rowCount());
} }
} }
return didEvaluate; return didEvaluate;

View File

@@ -49,15 +49,13 @@ class IEditor;
} }
namespace Debugger { namespace Debugger {
class QmlAdapter;
namespace Internal { namespace Internal {
class QtMessageLogItem; class QtMessageLogItem;
class QmlAdapter;
class QmlEnginePrivate; class QmlEnginePrivate;
class DEBUGGER_EXPORT QmlEngine : public DebuggerEngine class QmlEngine : public DebuggerEngine
{ {
Q_OBJECT Q_OBJECT

View 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

View 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

View 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

View 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

View File

@@ -30,36 +30,23 @@
** **
**************************************************************************/ **************************************************************************/
#include <typeinfo> #include "qmllivetextpreview.h"
#include "qmljsinspector.h" #include "qmlinspectoradapter.h"
#include "qmljsclientproxy.h" #include "qmlinspectoragent.h"
#include "qmljslivetextpreview.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/infobar.h>
#include <coreplugin/editormanager/ieditor.h> #include <qmldebug/basetoolsclient.h>
#include <coreplugin/id.h> #include <qmljseditor/qmljseditorconstants.h>
#include <coreplugin/editormanager/editormanager.h> #include <qmljs/parser/qmljsast_p.h>
#include <qmljs/qmljsdelta.h>
#include <debugger/debuggerconstants.h> #include <qmljs/qmljsmodelmanagerinterface.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <QDebug>
using namespace QmlJS; using namespace QmlJS;
using namespace QmlJS::AST; using namespace QmlJS::AST;
namespace QmlJSInspector { namespace Debugger {
namespace Internal { namespace Internal {
/*! /*!
@@ -70,10 +57,10 @@ class MapObjectWithDebugReference : public Visitor
public: public:
typedef QList<int> DebugIdList; typedef QList<int> DebugIdList;
MapObjectWithDebugReference() : activated(0) {} MapObjectWithDebugReference() : activated(0) {}
virtual void endVisit(UiObjectDefinition *ast) ; virtual void endVisit(UiObjectDefinition *ast);
virtual void endVisit(UiObjectBinding *ast) ; virtual void endVisit(UiObjectBinding *ast);
virtual bool visit(UiObjectDefinition *ast) ; virtual bool visit(UiObjectDefinition *ast);
virtual bool visit(UiObjectBinding *ast) ; virtual bool visit(UiObjectBinding *ast);
QHash<QPair<int, int>, DebugIdList> ids; QHash<QPair<int, int>, DebugIdList> ids;
QString filename; QString filename;
@@ -87,298 +74,6 @@ private:
int activated; 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 { class UpdateInspector : public Delta {
private: private:
static inline QString stripQuotes(const QString &str) static inline QString stripQuotes(const QString &str)
@@ -460,7 +155,7 @@ private:
ExpressionStatement *expStatement ExpressionStatement *expStatement
= cast<ExpressionStatement*>(scriptBinding->statement); = cast<ExpressionStatement*>(scriptBinding->statement);
switch(expStatement->expression->kind) { switch (expStatement->expression->kind) {
case Node::Kind_NumericLiteral: case Node::Kind_NumericLiteral:
case Node::Kind_UnaryPlusExpression: case Node::Kind_UnaryPlusExpression:
case Node::Kind_UnaryMinusExpression: case Node::Kind_UnaryMinusExpression:
@@ -491,7 +186,8 @@ protected:
Q_UNUSED(scriptBinding); Q_UNUSED(scriptBinding);
Q_UNUSED(parentDefinition); Q_UNUSED(parentDefinition);
appliedChangesToViewer = true; appliedChangesToViewer = true;
m_clientProxy->setMethodBodyForObject(debugId, methodName, methodBody); m_inspectorAdapter->engineClient()->setMethodBody(debugId,
methodName, methodBody);
} }
virtual void updateScriptBinding(DebugId debugId, virtual void updateScriptBinding(DebugId debugId,
@@ -501,11 +197,11 @@ protected:
const QString &scriptCode) const QString &scriptCode)
{ {
if (unsyncronizableChanges if (unsyncronizableChanges
== QmlJSLiveTextPreview::NoUnsyncronizableChanges) { == QmlLiveTextPreview::NoUnsyncronizableChanges) {
if (propertyName == QLatin1String("id")) { if (propertyName == QLatin1String("id")) {
unsyncronizableElementName = propertyName; unsyncronizableElementName = propertyName;
unsyncronizableChanges unsyncronizableChanges
= QmlJSLiveTextPreview::AttributeChangeWarning; = QmlLiveTextPreview::AttributeChangeWarning;
unsyncronizableChangeLine unsyncronizableChangeLine
= parentDefinition->firstSourceLocation().startLine; = parentDefinition->firstSourceLocation().startLine;
unsyncronizableChangeColumn unsyncronizableChangeColumn
@@ -518,7 +214,7 @@ protected:
if (isLiteral) if (isLiteral)
expr = castToLiteral(scriptCode, scriptBinding); expr = castToLiteral(scriptCode, scriptBinding);
appliedChangesToViewer = true; appliedChangesToViewer = true;
m_clientProxy->setBindingForObject( m_inspectorAdapter->engineClient()->setBindingForObject(
debugId, propertyName, expr, debugId, propertyName, expr,
isLiteral, document()->fileName(), isLiteral, document()->fileName(),
scriptBinding->firstSourceLocation().startLine); scriptBinding->firstSourceLocation().startLine);
@@ -527,13 +223,13 @@ protected:
virtual void resetBindingForObject(int debugId, const QString &propertyName) virtual void resetBindingForObject(int debugId, const QString &propertyName)
{ {
appliedChangesToViewer = true; appliedChangesToViewer = true;
m_clientProxy->resetBindingForObject(debugId, propertyName); m_inspectorAdapter->engineClient()->resetBindingForObject(debugId, propertyName);
} }
virtual void removeObject(int debugId) virtual void removeObject(int debugId)
{ {
appliedChangesToViewer = true; appliedChangesToViewer = true;
m_clientProxy->destroyQmlObject(debugId); m_inspectorAdapter->toolsClient()->destroyQmlObject(debugId);
} }
virtual void createObject(const QString &qmlText, DebugId ref, virtual void createObject(const QString &qmlText, DebugId ref,
@@ -543,18 +239,18 @@ protected:
{ {
appliedChangesToViewer = true; appliedChangesToViewer = true;
referenceRefreshRequired = 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) virtual void reparentObject(int debugId, int newParent)
{ {
appliedChangesToViewer = true; appliedChangesToViewer = true;
m_clientProxy->reparentQmlObject(debugId, newParent); m_inspectorAdapter->toolsClient()->reparentQmlObject(debugId, newParent);
} }
void notifyUnsyncronizableElementChange(UiObjectMember *parent) void notifyUnsyncronizableElementChange(UiObjectMember *parent)
{ {
if (unsyncronizableChanges == QmlJSLiveTextPreview::NoUnsyncronizableChanges) { if (unsyncronizableChanges == QmlLiveTextPreview::NoUnsyncronizableChanges) {
UiObjectDefinition *parentDefinition = cast<UiObjectDefinition *>(parent); UiObjectDefinition *parentDefinition = cast<UiObjectDefinition *>(parent);
if (parentDefinition && parentDefinition->qualifiedTypeNameId if (parentDefinition && parentDefinition->qualifiedTypeNameId
&& !parentDefinition->qualifiedTypeNameId->name.isEmpty()) && !parentDefinition->qualifiedTypeNameId->name.isEmpty())
@@ -562,7 +258,7 @@ protected:
unsyncronizableElementName unsyncronizableElementName
= parentDefinition->qualifiedTypeNameId->name.toString(); = parentDefinition->qualifiedTypeNameId->name.toString();
unsyncronizableChanges unsyncronizableChanges
= QmlJSLiveTextPreview::ElementChangeWarning; = QmlLiveTextPreview::ElementChangeWarning;
unsyncronizableChangeLine unsyncronizableChangeLine
= parentDefinition->firstSourceLocation().startLine; = parentDefinition->firstSourceLocation().startLine;
unsyncronizableChangeColumn unsyncronizableChangeColumn
@@ -572,30 +268,294 @@ protected:
} }
public: public:
UpdateInspector(ClientProxy *clientProxy) UpdateInspector(QmlInspectorAdapter *inspectorAdapter)
: appliedChangesToViewer(false) : appliedChangesToViewer(false)
, referenceRefreshRequired(false) , referenceRefreshRequired(false)
, unsyncronizableChanges(QmlJSLiveTextPreview::NoUnsyncronizableChanges) , unsyncronizableChanges(QmlLiveTextPreview::NoUnsyncronizableChanges)
, m_clientProxy(clientProxy) , m_inspectorAdapter(inspectorAdapter)
{ {
} }
bool appliedChangesToViewer; bool appliedChangesToViewer;
bool referenceRefreshRequired; bool referenceRefreshRequired;
QString unsyncronizableElementName; QString unsyncronizableElementName;
QmlJSLiveTextPreview::UnsyncronizableChangeType unsyncronizableChanges; QmlLiveTextPreview::UnsyncronizableChangeType unsyncronizableChanges;
unsigned unsyncronizableChangeLine; unsigned unsyncronizableChangeLine;
unsigned unsyncronizableChangeColumn; 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; 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) { if (m_applyChangesToQmlInspector) {
m_docWithUnappliedChanges.clear(); m_docWithUnappliedChanges.clear();
@@ -603,21 +563,14 @@ void QmlJSLiveTextPreview::documentChanged(QmlJS::Document::Ptr doc)
if (doc && m_previousDoc && doc->fileName() == m_previousDoc->fileName() if (doc && m_previousDoc && doc->fileName() == m_previousDoc->fileName()
&& doc->qmlProgram() && m_previousDoc->qmlProgram()) && doc->qmlProgram() && m_previousDoc->qmlProgram())
{ {
UpdateInspector delta(m_clientProxy.data()); UpdateInspector delta(m_inspectorAdapter);
m_debugIds = delta(m_previousDoc, doc, m_debugIds); m_debugIds = delta(m_previousDoc, doc, m_debugIds);
if (delta.referenceRefreshRequired) 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 if (delta.unsyncronizableChanges != NoUnsyncronizableChanges)
&& !experimentalWarningShown)
showSyncWarning(delta.unsyncronizableChanges, showSyncWarning(delta.unsyncronizableChanges,
delta.unsyncronizableElementName, delta.unsyncronizableElementName,
delta.unsyncronizableChangeLine, delta.unsyncronizableChangeLine,
@@ -627,30 +580,44 @@ void QmlJSLiveTextPreview::documentChanged(QmlJS::Document::Ptr doc)
if (!delta.newObjects.isEmpty()) if (!delta.newObjects.isEmpty())
m_createdObjects[doc] += delta.newObjects; m_createdObjects[doc] += delta.newObjects;
m_clientProxy.data()->clearComponentCache(); m_inspectorAdapter->toolsClient()->clearComponentCache();
} }
} else { } else {
m_docWithUnappliedChanges = doc; m_docWithUnappliedChanges = doc;
} }
} }
void QmlJSLiveTextPreview::showExperimentalWarning() QList<int> QmlLiveTextPreview::objectReferencesForOffset(quint32 offset)
{ {
foreach (QWeakPointer<TextEditor::BaseTextEditorWidget> editor, m_editors) QList<int> result;
if (editor) { QHashIterator<QmlJS::AST::UiObjectMember*, QList<int> > iter(m_debugIds);
Core::InfoBarEntry info( QmlJS::AST::UiObjectMember *possibleNode = 0;
Constants::INFO_EXPERIMENTAL, while (iter.hasNext()) {
tr("You changed a QML file in Live Preview mode, which " iter.next();
"modifies the running QML application. In case of " QmlJS::AST::UiObjectMember *member = iter.key();
"unexpected behavior, please reload the QML " quint32 startOffset = member->firstSourceLocation().offset;
"application.")); quint32 endOffset = member->lastSourceLocation().offset;
info.setCustomButtonInfo(tr("Disable Live Preview"), this, if (startOffset <= offset && offset <= endOffset) {
SLOT(disableLivePreview())); if (!possibleNode)
editor.data()->editorDocument()->infoBar()->addInfo(info); 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, UnsyncronizableChangeType unsyncronizableChangeType,
const QString &elementName, unsigned line, unsigned column) const QString &elementName, unsigned line, unsigned column)
{ {
@@ -666,87 +633,22 @@ void QmlJSLiveTextPreview::showSyncWarning(
"changed without reloading the QML application. ") "changed without reloading the QML application. ")
.arg(elementName, QString::number(line), QString::number(column)); .arg(elementName, QString::number(line), QString::number(column));
break; break;
case QmlJSLiveTextPreview::NoUnsyncronizableChanges: case QmlLiveTextPreview::NoUnsyncronizableChanges:
default: default:
return; return;
} }
errorMessage.append(tr("You can continue debugging, but behavior can be unexpected.")); 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) { if (editor) {
Core::InfoBar *infoBar = editor.data()->editorDocument()->infoBar(); Core::InfoBar *infoBar = editor->editorDocument()->infoBar();
infoBar->addInfo(Core::InfoBarEntry( infoBar->addInfo(Core::InfoBarEntry(
QLatin1String(Constants::INFO_OUT_OF_SYNC), QLatin1String("Debugger.Inspector.OutOfSyncWarning"),
errorMessage)); 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 Internal
} // namespace QmlJSInspector } // namespace Debugger

View File

@@ -30,21 +30,14 @@
** **
**************************************************************************/ **************************************************************************/
#ifndef SCRIPTBINDINGREWRITER_H #ifndef QMLLIVETEXTPREVIEW_H
#define SCRIPTBINDINGREWRITER_H #define QMLLIVETEXTPREVIEW_H
#include <QObject> #include <QObject>
#include <QWeakPointer>
#include <texteditor/basetexteditor.h> #include <texteditor/basetexteditor.h>
#include <qmldebug/baseenginedebugclient.h>
#include <qmljs/parser/qmljsastfwd_p.h>
#include <qmljs/qmljsdocument.h> #include <qmljs/qmljsdocument.h>
QT_FORWARD_DECLARE_CLASS(QTextDocument)
using namespace QmlDebug;
namespace Core { namespace Core {
class IEditor; class IEditor;
} }
@@ -53,41 +46,28 @@ namespace QmlJS {
class ModelManagerInterface; class ModelManagerInterface;
} }
namespace QmlJSInspector { namespace Debugger {
namespace Internal { namespace Internal {
class ClientProxy; class UpdateInspector;
class QmlInspectorAdapter;
class QmlLiveTextPreview : public QObject
class QmlJSLiveTextPreview : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit QmlJSLiveTextPreview(const QmlJS::Document::Ptr &doc, QmlLiveTextPreview(const QmlJS::Document::Ptr &doc,
const QmlJS::Document::Ptr &initDoc, const QmlJS::Document::Ptr &initDoc,
ClientProxy *clientProxy, QmlInspectorAdapter *inspectorAdapter,
QObject *parent = 0); QObject *parent = 0);
//void updateDocuments();
void associateEditor(Core::IEditor *editor); void associateEditor(Core::IEditor *editor);
void unassociateEditor(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 resetInitialDoc(const QmlJS::Document::Ptr &doc);
void setClientProxy(ClientProxy *clientProxy);
enum UnsyncronizableChangeType {
NoUnsyncronizableChanges,
AttributeChangeWarning,
ElementChangeWarning
};
signals: signals:
void selectedItemsChanged(const QList<QmlDebugObjectReference> &objects); void selectedItemsChanged(const QList<int> &debugIds);
void reloadQmlViewerRequested();
void disableLivePreviewRequested();
public slots: public slots:
void setApplyChangesToQmlInspector(bool applyChanges); void setApplyChangesToQmlInspector(bool applyChanges);
@@ -96,17 +76,18 @@ public slots:
private slots: private slots:
void changeSelectedElements(QList<int> offsets, const QString &wordAtCursor); void changeSelectedElements(QList<int> offsets, const QString &wordAtCursor);
void documentChanged(QmlJS::Document::Ptr doc); void documentChanged(QmlJS::Document::Ptr doc);
void disableLivePreview();
void reloadQmlViewer();
private: private:
enum UnsyncronizableChangeType {
NoUnsyncronizableChanges,
AttributeChangeWarning,
ElementChangeWarning
};
QList<int> objectReferencesForOffset(quint32 offset); QList<int> objectReferencesForOffset(quint32 offset);
QVariant castToLiteral(const QString &expression,
QmlJS::AST::UiScriptBinding *scriptBinding);
void showSyncWarning(UnsyncronizableChangeType unsyncronizableChangeType, void showSyncWarning(UnsyncronizableChangeType unsyncronizableChangeType,
const QString &elementName, const QString &elementName,
unsigned line, unsigned column); unsigned line, unsigned column);
void showExperimentalWarning();
private: private:
QHash<QmlJS::AST::UiObjectMember*, QList<int> > m_debugIds; QHash<QmlJS::AST::UiObjectMember*, QList<int> > m_debugIds;
@@ -114,20 +95,20 @@ private:
QmlJS::Document::Ptr m_previousDoc; QmlJS::Document::Ptr m_previousDoc;
QmlJS::Document::Ptr m_initialDoc; //the document that was loaded by the server 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; bool m_applyChangesToQmlInspector;
QmlJS::Document::Ptr m_docWithUnappliedChanges; QmlJS::Document::Ptr m_docWithUnappliedChanges;
QWeakPointer<ClientProxy> m_clientProxy; QmlInspectorAdapter *m_inspectorAdapter;
QList<int> m_lastOffsets; QList<int> m_lastOffsets;
QmlJS::AST::UiObjectMember *m_nodeForOffset; QmlJS::AST::UiObjectMember *m_nodeForOffset;
bool m_updateNodeForOffset; bool m_updateNodeForOffset;
friend class UpdateInspector;
}; };
} // namespace Internal } // namespace Internal
} // namespace QmlJSInspector } // namespace Debugger
#endif // SCRIPTBINDINGREWRITER_H #endif // QMLLIVETEXTPREVIEW_H

View File

@@ -172,6 +172,10 @@ WatchModel::WatchModel(WatchHandler *handler, WatchType type)
m_root->iname = "tooltip"; m_root->iname = "tooltip";
m_root->name = WatchHandler::tr("Tooltip"); m_root->name = WatchHandler::tr("Tooltip");
break; 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); WatchItem *item = watchItem(index);
QTC_ASSERT(item, return false); 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) void WatchModel::fetchMore(const QModelIndex &index)
@@ -713,6 +717,14 @@ int WatchModel::itemFormat(const WatchData &data) const
return theTypeFormats.value(stripForFormat(data.type), -1); 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) static inline QString expression(const WatchItem *item)
{ {
if (!item->exp.isEmpty()) 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 red(QColor(200, 0, 0));
static const QVariant gray(QColor(140, 140, 140)); static const QVariant gray(QColor(140, 140, 140));
switch (idx.column()) { switch (idx.column()) {
case 1: return (!data.valueEnabled || !m_handler->m_contentsValid) ? gray case 1: return (!data.valueEnabled || !contentIsValid()) ? gray
: data.changed ? red : QVariant(); : data.changed ? red : QVariant();
} }
break; break;
@@ -927,7 +939,7 @@ bool WatchModel::setData(const QModelIndex &index, const QVariant &value, int ro
Qt::ItemFlags WatchModel::flags(const QModelIndex &idx) const Qt::ItemFlags WatchModel::flags(const QModelIndex &idx) const
{ {
if (!m_handler->m_contentsValid) if (!contentIsValid())
return Qt::ItemFlags(); return Qt::ItemFlags();
if (!idx.isValid()) if (!idx.isValid())
@@ -1276,6 +1288,7 @@ WatchHandler::WatchHandler(DebuggerEngine *engine)
m_locals = new WatchModel(this, LocalsWatch); m_locals = new WatchModel(this, LocalsWatch);
m_watchers = new WatchModel(this, WatchersWatch); m_watchers = new WatchModel(this, WatchersWatch);
m_tooltips = new WatchModel(this, TooltipsWatch); m_tooltips = new WatchModel(this, TooltipsWatch);
m_inspect = new WatchModel(this, InspectWatch);
m_contentsValid = false; m_contentsValid = false;
m_resetLocationScheduled = false; m_resetLocationScheduled = false;
@@ -1294,6 +1307,7 @@ void WatchHandler::beginCycle(bool fullCycle)
m_locals->beginCycle(fullCycle); m_locals->beginCycle(fullCycle);
m_watchers->beginCycle(fullCycle); m_watchers->beginCycle(fullCycle);
m_tooltips->beginCycle(fullCycle); m_tooltips->beginCycle(fullCycle);
// don't sync m_inspect here: It's updated on it's own
} }
void WatchHandler::endCycle() void WatchHandler::endCycle()
@@ -1309,6 +1323,16 @@ void WatchHandler::endCycle()
updateWatchersWindow(); updateWatchersWindow();
} }
void WatchHandler::beginCycle(WatchType type, bool fullCycle)
{
model(type)->beginCycle(fullCycle);
}
void WatchHandler::endCycle(WatchType type)
{
model(type)->endCycle();
}
void WatchHandler::cleanup() void WatchHandler::cleanup()
{ {
m_expandedINames.clear(); m_expandedINames.clear();
@@ -1316,10 +1340,12 @@ void WatchHandler::cleanup()
m_return->reinitialize(); m_return->reinitialize();
m_locals->reinitialize(); m_locals->reinitialize();
m_tooltips->reinitialize(); m_tooltips->reinitialize();
m_inspect->reinitialize();
m_return->m_fetchTriggered.clear(); m_return->m_fetchTriggered.clear();
m_locals->m_fetchTriggered.clear(); m_locals->m_fetchTriggered.clear();
m_watchers->m_fetchTriggered.clear(); m_watchers->m_fetchTriggered.clear();
m_tooltips->m_fetchTriggered.clear(); m_tooltips->m_fetchTriggered.clear();
m_inspect->m_fetchTriggered.clear();
#if 1 #if 1
for (EditHandlers::ConstIterator it = m_editHandlers.begin(); for (EditHandlers::ConstIterator it = m_editHandlers.begin();
it != m_editHandlers.end(); ++it) { it != m_editHandlers.end(); ++it) {
@@ -1336,6 +1362,7 @@ void WatchHandler::emitAllChanged()
m_locals->emitAllChanged(); m_locals->emitAllChanged();
m_watchers->emitAllChanged(); m_watchers->emitAllChanged();
m_tooltips->emitAllChanged(); m_tooltips->emitAllChanged();
m_inspect->emitAllChanged();
} }
void WatchHandler::insertData(const WatchData &data) void WatchHandler::insertData(const WatchData &data)
@@ -1347,9 +1374,10 @@ void WatchHandler::insertData(const WatchData &data)
return; return;
} }
if (data.isSomethingNeeded() && data.iname.contains('.')) { if (data.isSomethingNeeded() && data.iname.contains(".")) {
MODEL_DEBUG("SOMETHING NEEDED: " << data.toString()); MODEL_DEBUG("SOMETHING NEEDED: " << data.toString());
if (!m_engine->isSynchronous()) { if (!m_engine->isSynchronous()
|| data.iname.startsWith("inspect.")) {
WatchModel *model = modelForIName(data.iname); WatchModel *model = modelForIName(data.iname);
QTC_ASSERT(model, return); QTC_ASSERT(model, return);
model->insertData(data); model->insertData(data);
@@ -1381,6 +1409,7 @@ void WatchHandler::reinsertAllData()
m_watchers->reinsertAllData(); m_watchers->reinsertAllData();
m_tooltips->reinsertAllData(); m_tooltips->reinsertAllData();
m_return->reinsertAllData(); m_return->reinsertAllData();
m_inspect->reinsertAllData();
} }
// Bulk-insertion // Bulk-insertion
@@ -1685,6 +1714,7 @@ WatchModel *WatchHandler::model(WatchType type) const
case LocalsWatch: return m_locals; case LocalsWatch: return m_locals;
case WatchersWatch: return m_watchers; case WatchersWatch: return m_watchers;
case TooltipsWatch: return m_tooltips; case TooltipsWatch: return m_tooltips;
case InspectWatch: return m_inspect;
} }
QTC_CHECK(false); QTC_CHECK(false);
return 0; return 0;
@@ -1700,6 +1730,8 @@ WatchModel *WatchHandler::modelForIName(const QByteArray &iname) const
return m_tooltips; return m_tooltips;
if (iname.startsWith("watch")) if (iname.startsWith("watch"))
return m_watchers; return m_watchers;
if (iname.startsWith("inspect"))
return m_inspect;
QTC_ASSERT(false, qDebug() << "INAME: " << iname); QTC_ASSERT(false, qDebug() << "INAME: " << iname);
return 0; return 0;
} }
@@ -1746,6 +1778,7 @@ void WatchHandler::setFormat(const QByteArray &type0, int format)
m_locals->emitDataChanged(1); m_locals->emitDataChanged(1);
m_watchers->emitDataChanged(1); m_watchers->emitDataChanged(1);
m_tooltips->emitDataChanged(1); m_tooltips->emitDataChanged(1);
m_inspect->emitDataChanged(1);
} }
int WatchHandler::format(const QByteArray &iname) const int WatchHandler::format(const QByteArray &iname) const
@@ -1905,6 +1938,7 @@ void WatchHandler::resetLocation()
m_locals->invalidateAll(); m_locals->invalidateAll();
m_watchers->invalidateAll(); m_watchers->invalidateAll();
m_tooltips->invalidateAll(); m_tooltips->invalidateAll();
m_inspect->invalidateAll();
} }
} }
@@ -1914,6 +1948,14 @@ bool WatchHandler::isValidToolTip(const QByteArray &iname) const
return item && !item->type.trimmed().isEmpty(); 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() QHash<QByteArray, int> WatchHandler::watcherNames()
{ {
return theWatcherNames; return theWatcherNames;

View File

@@ -55,7 +55,8 @@ enum WatchType
ReturnWatch, ReturnWatch,
LocalsWatch, LocalsWatch,
WatchersWatch, WatchersWatch,
TooltipsWatch TooltipsWatch,
InspectWatch
}; };
enum IntegerFormat enum IntegerFormat
@@ -78,6 +79,9 @@ public:
virtual int rowCount(const QModelIndex &idx = QModelIndex()) const; virtual int rowCount(const QModelIndex &idx = QModelIndex()) const;
virtual int columnCount(const QModelIndex &idx) const; virtual int columnCount(const QModelIndex &idx) const;
signals:
void setCurrentIndex(const QModelIndex &index);
private: private:
QVariant data(const QModelIndex &index, int role) const; QVariant data(const QModelIndex &index, int role) const;
bool setData(const QModelIndex &index, const QVariant &value, int role); bool setData(const QModelIndex &index, const QVariant &value, int role);
@@ -131,6 +135,7 @@ private:
DebuggerEngine *engine() const; DebuggerEngine *engine() const;
QString display(const WatchItem *item, int col) const; QString display(const WatchItem *item, int col) const;
int itemFormat(const WatchData &data) const; int itemFormat(const WatchData &data) const;
bool contentIsValid() const;
int m_generationCounter; int m_generationCounter;
WatchHandler *m_handler; WatchHandler *m_handler;
@@ -157,6 +162,10 @@ public:
void beginCycle(bool fullCycle = true); // Called at begin of updateLocals() cycle void beginCycle(bool fullCycle = true); // Called at begin of updateLocals() cycle
void updateWatchers(); // Called after locals are fetched void updateWatchers(); // Called after locals are fetched
void endCycle(); // Called after all results have been received 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 showEditValue(const WatchData &data);
void insertData(const WatchData &data); void insertData(const WatchData &data);
@@ -204,6 +213,8 @@ public:
void resetLocation(); void resetLocation();
bool isValidToolTip(const QByteArray &iname) const; bool isValidToolTip(const QByteArray &iname) const;
void setCurrentModelIndex(WatchType modelType, const QModelIndex &index);
private: private:
friend class WatchModel; friend class WatchModel;
@@ -230,6 +241,7 @@ private:
WatchModel *m_locals; WatchModel *m_locals;
WatchModel *m_watchers; WatchModel *m_watchers;
WatchModel *m_tooltips; WatchModel *m_tooltips;
WatchModel *m_inspect;
DebuggerEngine *m_engine; DebuggerEngine *m_engine;
int m_watcherCounter; int m_watcherCounter;

View File

@@ -994,11 +994,15 @@ void WatchTreeView::setModel(QAbstractItemModel *model)
setRootIsDecorated(true); setRootIsDecorated(true);
if (header()) { if (header()) {
header()->setDefaultAlignment(Qt::AlignLeft); header()->setDefaultAlignment(Qt::AlignLeft);
if (m_type != LocalsType) if (m_type != LocalsType && m_type != InspectType)
header()->hide(); header()->hide();
} }
connect(model, SIGNAL(layoutChanged()), SLOT(resetHelper())); connect(model, SIGNAL(layoutChanged()), SLOT(resetHelper()));
QTC_ASSERT(qobject_cast<WatchModel*>(model), return);
connect(model, SIGNAL(setCurrentIndex(QModelIndex)),
SLOT(setCurrentIndex(QModelIndex)));
} }
void WatchTreeView::resetHelper() void WatchTreeView::resetHelper()

View File

@@ -49,7 +49,7 @@ class WatchTreeView : public BaseTreeView
Q_OBJECT Q_OBJECT
public: public:
enum Type { ReturnType, LocalsType, TooltipType, WatchersType }; enum Type { ReturnType, LocalsType, TooltipType, WatchersType, InspectType };
explicit WatchTreeView(Type type, QWidget *parent = 0); explicit WatchTreeView(Type type, QWidget *parent = 0);
Type type() const { return m_type; } Type type() const { return m_type; }

View File

@@ -61,8 +61,7 @@ include(../../qtcreator.pri)
contains(QT_CONFIG, declarative)|contains(QT_CONFIG, quick1) { contains(QT_CONFIG, declarative)|contains(QT_CONFIG, quick1) {
SUBDIRS += \ SUBDIRS += \
plugin_qmlprojectmanager \ plugin_qmlprojectmanager
plugin_qmljsinspector
include(../private_headers.pri) include(../private_headers.pri)
exists($${QT_PRIVATE_HEADERS}/QtDeclarative/private/qdeclarativecontext_p.h) { 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_projectexplorer
plugin_debugger.depends += plugin_coreplugin plugin_debugger.depends += plugin_coreplugin
plugin_debugger.depends += plugin_cpptools plugin_debugger.depends += plugin_cpptools
plugin_debugger.depends += plugin_qmljstools
plugin_fakevim.subdir = fakevim plugin_fakevim.subdir = fakevim
plugin_fakevim.depends = plugin_coreplugin plugin_fakevim.depends = plugin_coreplugin
@@ -264,10 +264,6 @@ plugin_qmldesigner.depends += plugin_qt4projectmanager
plugin_qmldesigner.depends += plugin_qmlprojectmanager plugin_qmldesigner.depends += plugin_qmlprojectmanager
plugin_qmldesigner.depends += plugin_cpptools 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.subdir = mercurial
plugin_mercurial.depends = plugin_vcsbase plugin_mercurial.depends = plugin_vcsbase
plugin_mercurial.depends += plugin_projectexplorer plugin_mercurial.depends += plugin_projectexplorer

View File

@@ -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>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 735 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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)

View File

@@ -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",
]
}

View File

@@ -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>

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 &paramName,
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 &paramName,
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