forked from qt-creator/qt-creator
QmlInspector: tooltips in qmldebug mode
Reviewed by: Lasse Holmstedt
This commit is contained in:
@@ -30,6 +30,7 @@
|
||||
#include "qmlengine.h"
|
||||
#include "qmladapter.h"
|
||||
|
||||
#include "debuggertooltip.h"
|
||||
#include "debuggerconstants.h"
|
||||
#include "debuggerplugin.h"
|
||||
#include "debuggerdialogs.h"
|
||||
@@ -170,6 +171,7 @@ void QmlEngine::connectionEstablished()
|
||||
|
||||
ExtensionSystem::PluginManager *pluginManager = ExtensionSystem::PluginManager::instance();
|
||||
pluginManager->addObject(m_adapter);
|
||||
pluginManager->addObject(this);
|
||||
m_addedAdapterToObjectPool = true;
|
||||
|
||||
plugin()->showMessage(tr("QML Debugger connected."), StatusBar);
|
||||
@@ -233,6 +235,7 @@ void QmlEngine::shutdownEngineAsSlave()
|
||||
if (m_addedAdapterToObjectPool) {
|
||||
ExtensionSystem::PluginManager *pluginManager = ExtensionSystem::PluginManager::instance();
|
||||
pluginManager->removeObject(m_adapter);
|
||||
pluginManager->removeObject(this);
|
||||
}
|
||||
|
||||
if (m_attachToRunningExternalApp) {
|
||||
@@ -445,9 +448,8 @@ static QHash<QString, WatchData> m_toolTipCache;
|
||||
|
||||
void QmlEngine::setToolTipExpression(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos)
|
||||
{
|
||||
Q_UNUSED(mousePos)
|
||||
Q_UNUSED(editor)
|
||||
Q_UNUSED(cursorPos)
|
||||
// this is processed by QML inspector, which has deps to qml js editor. Makes life easier.
|
||||
emit tooltipRequested(mousePos, editor, cursorPos);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -46,6 +46,10 @@
|
||||
|
||||
#include <projectexplorer/applicationlauncher.h>
|
||||
|
||||
namespace Core {
|
||||
class TextEditor;
|
||||
}
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
|
||||
@@ -120,6 +124,7 @@ private:
|
||||
|
||||
signals:
|
||||
void sendMessage(const QByteArray &msg);
|
||||
void tooltipRequested(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos);
|
||||
|
||||
private slots:
|
||||
void connectionEstablished();
|
||||
|
||||
@@ -116,7 +116,7 @@ public: // attributes
|
||||
|
||||
class SemanticHighlighter;
|
||||
|
||||
class SemanticInfo
|
||||
class QMLJSEDITOR_EXPORT SemanticInfo
|
||||
{
|
||||
public:
|
||||
SemanticInfo() {}
|
||||
|
||||
@@ -198,6 +198,29 @@ QDeclarativeDebugObjectReference ClientProxy::objectReferenceForId(int debugId,
|
||||
return QDeclarativeDebugObjectReference();
|
||||
}
|
||||
|
||||
QDeclarativeDebugObjectReference ClientProxy::objectReferenceForId(const QString &objectId) const
|
||||
{
|
||||
if (!objectId.isEmpty() && objectId[0].isLower()) {
|
||||
const QList<QDeclarativeDebugObjectReference> refs = objectReferences();
|
||||
foreach (const QDeclarativeDebugObjectReference &ref, refs) {
|
||||
if (ref.idString() == objectId)
|
||||
return ref;
|
||||
}
|
||||
}
|
||||
return QDeclarativeDebugObjectReference();
|
||||
}
|
||||
|
||||
QDeclarativeDebugObjectReference ClientProxy::objectReferenceForLocation(const int line, const int column) const
|
||||
{
|
||||
const QList<QDeclarativeDebugObjectReference> refs = objectReferences();
|
||||
foreach (const QDeclarativeDebugObjectReference &ref, refs) {
|
||||
if (ref.source().lineNumber() == line && ref.source().columnNumber() == column)
|
||||
return ref;
|
||||
}
|
||||
|
||||
return QDeclarativeDebugObjectReference();
|
||||
}
|
||||
|
||||
QList<QDeclarativeDebugObjectReference> ClientProxy::objectReferences() const
|
||||
{
|
||||
QList<QDeclarativeDebugObjectReference> result;
|
||||
@@ -253,6 +276,13 @@ bool ClientProxy::resetBindingForObject(int objectDebugId, const QString& proper
|
||||
return m_client->resetBindingForObject(objectDebugId, propertyName);
|
||||
}
|
||||
|
||||
QDeclarativeDebugExpressionQuery *ClientProxy::queryExpressionResult(int objectDebugId, const QString &expr, QObject *parent)
|
||||
{
|
||||
if (objectDebugId != -1)
|
||||
return m_client->queryExpressionResult(objectDebugId,expr,parent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ClientProxy::clearComponentCache()
|
||||
{
|
||||
if (isDesignClientConnected())
|
||||
|
||||
@@ -65,11 +65,14 @@ public:
|
||||
|
||||
bool setMethodBodyForObject(int objectDebugId, const QString &methodName, const QString &methodBody);
|
||||
bool resetBindingForObject(int objectDebugId, const QString &propertyName);
|
||||
QDeclarativeDebugExpressionQuery *queryExpressionResult(int objectDebugId, const QString &expr, QObject *parent=0);
|
||||
void clearComponentCache();
|
||||
|
||||
// returns the object references
|
||||
QList<QDeclarativeDebugObjectReference> objectReferences() const;
|
||||
QDeclarativeDebugObjectReference objectReferenceForId(int debugId) const;
|
||||
QDeclarativeDebugObjectReference objectReferenceForId(const QString &objectId) const;
|
||||
QDeclarativeDebugObjectReference objectReferenceForLocation(const int line, const int column) const;
|
||||
QList<QDeclarativeDebugObjectReference> rootObjectReference() const;
|
||||
DebugIdHash debugIdHash() const { return m_debugIdHash; };
|
||||
|
||||
|
||||
@@ -38,9 +38,11 @@
|
||||
|
||||
#include <qmljseditor/qmljseditorconstants.h>
|
||||
|
||||
#include <qmljseditor/qmljseditor.h>
|
||||
#include <qmljs/qmljsmodelmanagerinterface.h>
|
||||
#include <qmljs/qmljsdocument.h>
|
||||
|
||||
#include <qmljs/parser/qmljsast_p.h>
|
||||
#include <debugger/debuggerrunner.h>
|
||||
#include <debugger/debuggerconstants.h>
|
||||
#include <debugger/debuggerengine.h>
|
||||
@@ -49,6 +51,7 @@
|
||||
#include <debugger/debuggerrunner.h>
|
||||
#include <debugger/debuggeruiswitcher.h>
|
||||
#include <debugger/debuggerconstants.h>
|
||||
#include <debugger/qml/qmlengine.h>
|
||||
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/styledbar.h>
|
||||
@@ -100,6 +103,8 @@
|
||||
#include <QtGui/QMessageBox>
|
||||
#include <QtGui/QTextBlock>
|
||||
|
||||
#include <QtGui/QToolTip>
|
||||
#include <QtGui/QCursor>
|
||||
#include <QtNetwork/QHostAddress>
|
||||
|
||||
using namespace QmlJS;
|
||||
@@ -131,6 +136,8 @@ InspectorUi::InspectorUi(QObject *parent)
|
||||
, m_inspectorDockWidget(0)
|
||||
, m_settings(new InspectorSettings(this))
|
||||
, m_clientProxy(0)
|
||||
, m_qmlEngine(0)
|
||||
, m_debugQuery(0)
|
||||
, m_debugProject(0)
|
||||
{
|
||||
m_instance = this;
|
||||
@@ -157,6 +164,103 @@ void InspectorUi::restoreSettings()
|
||||
m_settings->restoreSettings(Core::ICore::instance()->settings());
|
||||
}
|
||||
|
||||
void InspectorUi::setDebuggerEngine(Debugger::Internal::QmlEngine *qmlEngine)
|
||||
{
|
||||
if (m_qmlEngine && !qmlEngine) {
|
||||
disconnect(m_qmlEngine, SIGNAL(tooltipRequested(QPoint, TextEditor::ITextEditor*, int)),
|
||||
this, SLOT(showDebuggerTooltip(QPoint, TextEditor::ITextEditor*, int)));
|
||||
}
|
||||
|
||||
m_qmlEngine = qmlEngine;
|
||||
if (m_qmlEngine) {
|
||||
connect(m_qmlEngine, SIGNAL(tooltipRequested(QPoint, TextEditor::ITextEditor*, int)),
|
||||
this, SLOT(showDebuggerTooltip(QPoint, TextEditor::ITextEditor*, int)));
|
||||
}
|
||||
}
|
||||
|
||||
Debugger::Internal::QmlEngine *InspectorUi::debuggerEngine() const
|
||||
{
|
||||
return m_qmlEngine;
|
||||
}
|
||||
|
||||
void InspectorUi::showDebuggerTooltip(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos)
|
||||
{
|
||||
Q_UNUSED(mousePos);
|
||||
if (editor->id() == QmlJSEditor::Constants::C_QMLJSEDITOR_ID) {
|
||||
QmlJSEditor::Internal::QmlJSTextEditor *qmlEditor = static_cast<QmlJSEditor::Internal::QmlJSTextEditor*>(editor->widget());
|
||||
|
||||
QTextCursor tc(qmlEditor->document());
|
||||
tc.setPosition(cursorPos);
|
||||
tc.movePosition(QTextCursor::StartOfWord);
|
||||
tc.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
|
||||
|
||||
QString wordAtCursor = tc.selectedText();
|
||||
QString query;
|
||||
QLatin1Char doubleQuote('"');
|
||||
|
||||
QmlJS::AST::Node *qmlNode = qmlEditor->semanticInfo().nodeUnderCursor(cursorPos);
|
||||
if (!qmlNode)
|
||||
return;
|
||||
QmlJS::AST::Node *node = qmlEditor->semanticInfo().declaringMemberNoProperties(cursorPos);
|
||||
if (!node)
|
||||
return;
|
||||
QDeclarativeDebugObjectReference ref = m_clientProxy->objectReferenceForLocation(node->uiObjectMemberCast()->firstSourceLocation().startLine, node->uiObjectMemberCast()->firstSourceLocation().startColumn);
|
||||
|
||||
if (ref.debugId() == -1)
|
||||
return;
|
||||
|
||||
if (wordAtCursor == QString("id")) {
|
||||
query = QString("\"id:") + ref.idString() + doubleQuote;
|
||||
} else {
|
||||
if ((qmlNode->kind == QmlJS::AST::Node::Kind_IdentifierExpression) ||
|
||||
(qmlNode->kind == QmlJS::AST::Node::Kind_FieldMemberExpression)) {
|
||||
tc.setPosition(qmlNode->expressionCast()->firstSourceLocation().begin());
|
||||
tc.setPosition(qmlNode->expressionCast()->lastSourceLocation().end(),QTextCursor::KeepAnchor);
|
||||
QString refToLook = tc.selectedText();
|
||||
if ((qmlNode->kind == QmlJS::AST::Node::Kind_IdentifierExpression) &&
|
||||
(m_clientProxy->objectReferenceForId(refToLook).debugId() == -1)) {
|
||||
query = doubleQuote + QString("local: ") + refToLook + doubleQuote;
|
||||
foreach(QDeclarativeDebugPropertyReference property, ref.properties()) {
|
||||
if (property.name() == wordAtCursor && !property.valueTypeName().isEmpty()) {
|
||||
query = doubleQuote + property.name() + QLatin1Char(':') + doubleQuote + QLatin1Char('+') + property.name();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
query =doubleQuote + refToLook + QLatin1Char(':') + doubleQuote + QLatin1Char('+') + refToLook;
|
||||
} else {
|
||||
// show properties
|
||||
foreach(QDeclarativeDebugPropertyReference property, ref.properties()) {
|
||||
if (property.name() == wordAtCursor && !property.valueTypeName().isEmpty()) {
|
||||
query = doubleQuote + property.name() + QLatin1Char(':') + doubleQuote + QLatin1Char('+') + property.name();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!query.isEmpty()) {
|
||||
m_debugQuery = m_clientProxy->queryExpressionResult(ref.debugId(),query);
|
||||
connect(m_debugQuery,SIGNAL(stateChanged(QDeclarativeDebugQuery::State)),this,SLOT(debugQueryUpdated(QDeclarativeDebugQuery::State)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InspectorUi::debugQueryUpdated(QDeclarativeDebugQuery::State newState)
|
||||
{
|
||||
if (newState != QDeclarativeDebugExpressionQuery::Completed)
|
||||
return;
|
||||
if (!m_debugQuery)
|
||||
return;
|
||||
|
||||
QString text = m_debugQuery->result().toString();
|
||||
if (!text.isEmpty())
|
||||
QToolTip::showText(QCursor::pos(), text);
|
||||
|
||||
disconnect(m_debugQuery,SIGNAL(stateChanged(QDeclarativeDebugQuery::State)),this,SLOT(debugQueryUpdated(QDeclarativeDebugQuery::State)));
|
||||
}
|
||||
|
||||
void InspectorUi::connected(ClientProxy *clientProxy)
|
||||
{
|
||||
m_clientProxy = clientProxy;
|
||||
@@ -203,6 +307,7 @@ void InspectorUi::disconnected()
|
||||
m_crumblePath, SLOT(updateContextPath(QStringList)));
|
||||
|
||||
m_debugProject = 0;
|
||||
m_qmlEngine = 0;
|
||||
resetViews();
|
||||
|
||||
setupToolbar(false);
|
||||
|
||||
@@ -47,6 +47,10 @@ namespace ProjectExplorer {
|
||||
class Environment;
|
||||
}
|
||||
|
||||
namespace TextEditor {
|
||||
class ITextEditor;
|
||||
}
|
||||
|
||||
namespace Core {
|
||||
class IContext;
|
||||
}
|
||||
@@ -55,6 +59,12 @@ namespace QmlJS {
|
||||
class ModelManagerInterface;
|
||||
}
|
||||
|
||||
namespace Debugger {
|
||||
namespace Internal {
|
||||
class QmlEngine;
|
||||
}
|
||||
}
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QDockWidget)
|
||||
|
||||
namespace QmlJSInspector {
|
||||
@@ -97,6 +107,8 @@ public:
|
||||
void setupUi();
|
||||
void connected(ClientProxy *clientProxy);
|
||||
void disconnected();
|
||||
void setDebuggerEngine(Debugger::Internal::QmlEngine *qmlEngine);
|
||||
Debugger::Internal::QmlEngine *debuggerEngine() const;
|
||||
|
||||
signals:
|
||||
void statusMessage(const QString &text);
|
||||
@@ -125,6 +137,8 @@ private slots:
|
||||
|
||||
void currentDebugProjectRemoved();
|
||||
void updatePendingPreviewDocuments(QmlJS::Document::Ptr doc);
|
||||
void showDebuggerTooltip(const QPoint &mousePos, TextEditor::ITextEditor *editor, int cursorPos);
|
||||
void debugQueryUpdated(QDeclarativeDebugQuery::State);
|
||||
|
||||
private:
|
||||
bool addQuotesForData(const QVariant &value) const;
|
||||
@@ -146,6 +160,8 @@ private:
|
||||
|
||||
InspectorSettings *m_settings;
|
||||
ClientProxy *m_clientProxy;
|
||||
Debugger::Internal::QmlEngine *m_qmlEngine;
|
||||
QDeclarativeDebugExpressionQuery *m_debugQuery;
|
||||
|
||||
// Qml/JS integration
|
||||
QHash<QString, QmlJSLiveTextPreview *> m_textPreviews;
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include <debugger/debuggeruiswitcher.h>
|
||||
#include <debugger/debuggerconstants.h>
|
||||
#include <debugger/qml/qmladapter.h>
|
||||
#include <debugger/qml/qmlengine.h>
|
||||
|
||||
#include <qmlprojectmanager/qmlproject.h>
|
||||
#include <qmljseditor/qmljseditorconstants.h>
|
||||
@@ -130,6 +131,12 @@ void InspectorPlugin::objectAdded(QObject *object)
|
||||
if (adapter) {
|
||||
m_clientProxy = new ClientProxy(adapter);
|
||||
m_inspectorUi->connected(m_clientProxy);
|
||||
return;
|
||||
}
|
||||
|
||||
Debugger::Internal::QmlEngine *engine = qobject_cast<Debugger::Internal::QmlEngine*>(object);
|
||||
if (engine) {
|
||||
m_inspectorUi->setDebuggerEngine(engine);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,6 +147,10 @@ void InspectorPlugin::aboutToRemoveObject(QObject *obj)
|
||||
delete m_clientProxy;
|
||||
m_clientProxy = 0;
|
||||
}
|
||||
|
||||
if (m_inspectorUi->debuggerEngine() == obj) {
|
||||
m_inspectorUi->setDebuggerEngine(0);
|
||||
}
|
||||
}
|
||||
|
||||
Q_EXPORT_PLUGIN(InspectorPlugin)
|
||||
|
||||
@@ -206,15 +206,7 @@ void QmlJSLiveTextPreview::changeSelectedElements(QList<int> offsets, const QStr
|
||||
return;
|
||||
|
||||
QDeclarativeDebugObjectReference objectRefUnderCursor;
|
||||
if (!wordAtCursor.isEmpty() && wordAtCursor[0].isLower()) {
|
||||
QList<QDeclarativeDebugObjectReference> refs = m_clientProxy.data()->objectReferences();
|
||||
foreach (const QDeclarativeDebugObjectReference &ref, refs) {
|
||||
if (ref.idString() == wordAtCursor) {
|
||||
objectRefUnderCursor = ref;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
objectRefUnderCursor = m_clientProxy.data()->objectReferenceForId(wordAtCursor);
|
||||
|
||||
QList<int> selectedReferences;
|
||||
bool containsReferenceUnderCursor = false;
|
||||
|
||||
Reference in New Issue
Block a user