Commit 1c702357 authored by Christiaan Janssen's avatar Christiaan Janssen
Browse files

QmlInspector: tooltips in qmldebug mode

Reviewed by: Lasse Holmstedt
parent 0a33abf0
......@@ -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;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment