diff --git a/src/plugins/qmljsinspector/qmljsdelta.cpp b/src/plugins/qmljsinspector/qmljsdelta.cpp index d31e7ce99e73622c815609b40191ac3345aad07c..491571cd3d973ad8768af9065c6a0654cf4c981e 100644 --- a/src/plugins/qmljsinspector/qmljsdelta.cpp +++ b/src/plugins/qmljsinspector/qmljsdelta.cpp @@ -39,66 +39,309 @@ using namespace QmlJS; using namespace QmlJS::AST; using namespace QmlJSInspector::Internal; -UiObjectMember *ScriptBindingParser::parent(UiScriptBinding *script) const -{ return _parent.value(script); } - -UiScriptBinding *ScriptBindingParser::id(UiObjectMember *parent) const -{ return _id.value(parent); } +/*! + Build a hash of the parents + */ +struct BuildParentHash : public Visitor +{ + virtual void postVisit(Node* ); + virtual bool preVisit(Node* ); + QHash<UiObjectMember *, UiObjectMember *> parent; +private: + QList<UiObjectMember *> stack; +}; + +bool BuildParentHash::preVisit(Node* ast) +{ + if (ast->uiObjectMemberCast()) { + stack.append(ast->uiObjectMemberCast()); + } + return true; +} -QList<UiScriptBinding *> ScriptBindingParser::ids() const -{ return _id.values(); } -QString ScriptBindingParser::header(UiObjectMember *member) const +void BuildParentHash::postVisit(Node* ast) { - if (member) { - if (UiObjectDefinition *def = cast<UiObjectDefinition *>(member)) { - const int begin = def->firstSourceLocation().begin(); - const int end = def->initializer->lbraceToken.begin(); - return doc->source().mid(begin, end - begin); - } else if (UiObjectBinding *binding = cast<UiObjectBinding *>(member)) { - const int begin = binding->firstSourceLocation().begin(); - const int end = binding->initializer->lbraceToken.begin(); - return doc->source().mid(begin, end - begin); + if (ast->uiObjectMemberCast()) { + stack.removeLast(); + if (!stack.isEmpty()) { + parent.insert(ast->uiObjectMemberCast(), stack.last()); } } +} - return QString(); +QString label(UiObjectMember *member, Document::Ptr doc) +{ + QString str; + if(!member) + return str; + + if (UiObjectDefinition* foo = cast<UiObjectDefinition *>(member)) { + quint32 start = foo->firstSourceLocation().begin(); + quint32 end = foo->initializer->lbraceToken.begin(); + str = doc->source().mid(start, end-start); + } else if(UiObjectBinding *foo = cast<UiObjectBinding *>(member)) { + quint32 start = foo->firstSourceLocation().begin(); + quint32 end = foo->initializer->lbraceToken.begin(); + str = doc->source().mid(start, end-start); + } else if(cast<UiArrayBinding *>(member)) { + //TODO + } else { + quint32 start = member->firstSourceLocation().begin(); + quint32 end = member->lastSourceLocation().end(); + str = doc->source().mid(start, end-start); + } + return str; } -QString ScriptBindingParser::scriptCode(UiScriptBinding *script) const +struct FindObjectMemberWithLabel : public Visitor +{ + virtual void endVisit(UiObjectDefinition *ast) ; + virtual void endVisit(UiObjectBinding *ast) ; + + QList<UiObjectMember *> found; + QString cmp; + Document::Ptr doc; +}; + +void FindObjectMemberWithLabel::endVisit(UiObjectDefinition* ast) +{ + if (label(ast, doc) == cmp) + found.append(ast); +} +void FindObjectMemberWithLabel::endVisit(UiObjectBinding* ast) +{ + if (label(ast, doc) == cmp) + found.append(ast); +} + +struct Map { + typedef UiObjectMember*T; + QHash<T, T> way1; + QHash<T, T> way2; + void insert(T t1, T t2) { + way1.insert(t1,t2); + way2.insert(t2,t1); + } + int count() { return way1.count(); } + void operator+=(const Map &other) { + way1.unite(other.way1); + way2.unite(other.way2); + } + bool contains(T t1, T t2) { + return way1.value(t1) == t2; + } +}; + +QList<UiObjectMember *> children(UiObjectMember *ast) +{ + QList<UiObjectMember *> ret; + if (UiObjectDefinition* foo = cast<UiObjectDefinition *>(ast)) { + UiObjectMemberList* list = foo->initializer->members; + while (list) { + ret.append(list->member); + list = list->next; + } + } + return ret; +} + +Map MatchFragment(UiObjectMember *x, UiObjectMember *y, const Map &M, Document::Ptr doc1, Document::Ptr doc2) { + Map M2; + if (M.way1.contains(x)) + return M2; + if (M.way2.contains(y)) + return M2; + if(label(x, doc1) != label(y, doc2)) + return M2; + M2.insert(x, y); + const QList<UiObjectMember *> list1 = children(x); + const QList<UiObjectMember *> list2 = children(y); + for (int i = 0; i < qMin(list1.count(), list2.count()); i++) { + M2 += MatchFragment(list1[i], list2[i], M, doc1, doc2); + } + return M2; +} + +Map Mapping(Document::Ptr doc1, Document::Ptr doc2) +{ + Map M; + QList<UiObjectMember *> todo; + todo.append(doc1->qmlProgram()->members->member); + while(!todo.isEmpty()) { + UiObjectMember *x = todo.takeFirst(); + todo += children(x); + + if (M.way1.contains(x)) + continue; + + //If this is too slow, we could use some sort of indexing + FindObjectMemberWithLabel v3; + v3.cmp = label(x, doc1); + v3.doc = doc2; + doc2->qmlProgram()->accept(&v3); + Map M2; + foreach (UiObjectMember *y, v3.found) { + if (M.way2.contains(y)) + continue; + Map M3 = MatchFragment(x, y, M, doc1, doc2); + if (M3.count() > M2.count()) + M2 = M3; + } + M += M2; + } + return M; +} + + +static QString _scriptCode(UiScriptBinding *script, Document::Ptr doc) { if (script) { const int begin = script->statement->firstSourceLocation().begin(); const int end = script->statement->lastSourceLocation().end(); return doc->source().mid(begin, end - begin); } - return QString(); } - -QString ScriptBindingParser::methodName(UiSourceElement *source) const +static QString _methodCode(UiSourceElement *source, Document::Ptr doc) { if (source) { if (FunctionDeclaration *declaration = cast<FunctionDeclaration*>(source->sourceElement)) { - return declaration->name->asString(); + const int begin = declaration->lbraceToken.begin() + 1; + const int end = declaration->rbraceToken.end() - 1; + return doc->source().mid(begin, end - begin); } } return QString(); } -QString ScriptBindingParser::methodCode(UiSourceElement *source) const + +static QString _propertyName(UiQualifiedId *id) +{ + QString s; + + for (; id; id = id->next) { + if (! id->name) + return QString(); + + s += id->name->asString(); + + if (id->next) + s += QLatin1Char('.'); + } + + return s; +} + +static QString _methodName(UiSourceElement *source) { if (source) { if (FunctionDeclaration *declaration = cast<FunctionDeclaration*>(source->sourceElement)) { - const int begin = declaration->lbraceToken.begin() + 1; - const int end = declaration->rbraceToken.end() - 1; - return doc->source().mid(begin, end - begin); + return declaration->name->asString(); } } return QString(); } + + +Delta::DebugIdMap Delta::operator()(Document::Ptr doc1, Document::Ptr doc2, const DebugIdMap &debugIds) +{ + QHash< UiObjectMember*, QList<QDeclarativeDebugObjectReference > > newDebuggIds; + + Map M = Mapping(doc1, doc2); + + BuildParentHash parents2; + doc2->qmlProgram()->accept(&parents2); + BuildParentHash parents1; + doc1->qmlProgram()->accept(&parents1); + + QList<UiObjectMember *> todo; + todo.append(doc2->qmlProgram()->members->member); + //UiObjectMemberList *list = 0; + while(!todo.isEmpty()) { + UiObjectMember *y = todo.takeFirst(); + todo += children(y); + if (!M.way2.contains(y)) { + qDebug () << "insert " << label(y, doc2) << " to " << label(parents2.parent.value(y), doc2); + continue; + } + UiObjectMember *x = M.way2[y]; + + +//--8<--------------------------------------------------------------------------------------- + if (debugIds.contains(x)) { + newDebuggIds[y] = debugIds[x]; + + UiObjectMember *object = y; + UiObjectMember *previousObject = x; + + for (UiObjectMemberList *objectMemberIt = objectMembers(object); objectMemberIt; objectMemberIt = objectMemberIt->next) { + if (UiScriptBinding *script = cast<UiScriptBinding *>(objectMemberIt->member)) { + for (UiObjectMemberList *previousObjectMemberIt = Delta::objectMembers(previousObject); previousObjectMemberIt; previousObjectMemberIt = previousObjectMemberIt->next) { + if (UiScriptBinding *previousScript = cast<UiScriptBinding *>(previousObjectMemberIt->member)) { + if (compare(script->qualifiedId, previousScript->qualifiedId)) { + const QString scriptCode = _scriptCode(script, doc2); + const QString previousScriptCode = _scriptCode(previousScript, doc1); + + if (scriptCode != previousScriptCode) { + const QString property = _propertyName(script->qualifiedId); + foreach (const QDeclarativeDebugObjectReference &ref, debugIds[x]) { + if (ref.debugId() != -1) + updateScriptBinding(ref, script, property, scriptCode); + } + } + } + } + } + } else if (UiSourceElement *uiSource = cast<UiSourceElement*>(objectMemberIt->member)) { + for (UiObjectMemberList *previousObjectMemberIt = objectMembers(previousObject); + previousObjectMemberIt; previousObjectMemberIt = previousObjectMemberIt->next) + { + if (UiSourceElement *previousSource = cast<UiSourceElement*>(previousObjectMemberIt->member)) { + if (compare(uiSource, previousSource)) + { + const QString methodCode = _methodCode(uiSource, doc2); + const QString previousMethodCode = _methodCode(previousSource, doc1); + + if (methodCode != previousMethodCode) { + const QString methodName = _methodName(uiSource); + foreach (const QDeclarativeDebugObjectReference &ref, debugIds[x]) { + if (ref.debugId() != -1) + updateMethodBody(ref, script, methodName, methodCode); + } + } + } + } + } + } + } + } + +//--8<-------------------------------------------------------------------------------------------------- + + //qDebug() << "match "<< label(x, doc1) << "with parent " << label(parents1.parent.value(x), doc1) + // << " to "<< label(y, doc2) << "with parent " << label(parents2.parent.value(y), doc2); + if (!M.contains(parents1.parent.value(x),parents2.parent.value(y))) { + qDebug () << "move " << label(y, doc2) << " from " << label(parents1.parent.value(x), doc1) + << " to " << label(parents2.parent.value(y), doc2); + continue; + } + } + + todo.append(doc1->qmlProgram()->members->member); + while(!todo.isEmpty()) { + UiObjectMember *x = todo.takeFirst(); + todo += children(x); + if (!M.way1.contains(x)) { + qDebug () << "remove " << label(x, doc1); + continue; + } + } + return newDebuggIds; +} + static bool isLiteralValue(ExpressionNode *expr) { if (cast<NumericLiteral*>(expr)) @@ -191,227 +434,6 @@ static QVariant castToLiteral(const QString &expression, UiScriptBinding *script return castedExpression; } -ScriptBindingParser::ScriptBindingParser(QmlJS::Document::Ptr doc, - const QList<QDeclarativeDebugObjectReference> &objectReferences) - : doc(doc), objectReferences(objectReferences), m_searchElementOffset(-1) -{ - -} - -void ScriptBindingParser::process() -{ - if (!doc.isNull() && doc->qmlProgram()) - doc->qmlProgram()->accept(this); -} - -QDeclarativeDebugObjectReference ScriptBindingParser::objectReferenceForOffset(unsigned int offset) -{ - m_searchElementOffset = offset; - if (!doc.isNull() && doc->qmlProgram()) - doc->qmlProgram()->accept(this); - - return m_foundObjectReference; -} - -QDeclarativeDebugObjectReference ScriptBindingParser::objectReference(const QString &id) const -{ - foreach (const QDeclarativeDebugObjectReference &ref, objectReferences) { - if (ref.idString() == id) - return ref; - } - - return QDeclarativeDebugObjectReference(); -} - - -QDeclarativeDebugObjectReference ScriptBindingParser::objectReferenceForPosition(const QUrl &url, int line, int col) const -{ - foreach (const QDeclarativeDebugObjectReference &ref, objectReferences) { - if (ref.source().lineNumber() == line - && ref.source().columnNumber() == col - && ref.source().url() == url) - { - return ref; - } - } - - return QDeclarativeDebugObjectReference(); -} - -bool ScriptBindingParser::visit(UiObjectDefinition *ast) -{ - objectStack.append(ast); - return true; -} - -void ScriptBindingParser::endVisit(UiObjectDefinition *) -{ - objectStack.removeLast(); -} - -bool ScriptBindingParser::visit(UiObjectBinding *ast) -{ - objectStack.append(ast); - return true; -} - -void ScriptBindingParser::endVisit(UiObjectBinding *) -{ - objectStack.removeLast(); -} - -bool ScriptBindingParser::visit(UiScriptBinding *ast) -{ - scripts.append(ast); - _parent[ast] = objectStack.back(); - - if (ast->qualifiedId && ast->qualifiedId->name && ! ast->qualifiedId->next) { - const QString bindingName = ast->qualifiedId->name->asString(); - - if (bindingName == QLatin1String("id")) { - _id[objectStack.back()] = ast; - - if (ExpressionStatement *s = cast<ExpressionStatement *>(ast->statement)) { - if (IdentifierExpression *id = cast<IdentifierExpression *>(s->expression)) { - if (id->name) { - _idBindings.insert(ast, objectReference(id->name->asString())); - - if (parent(ast)->firstSourceLocation().offset == m_searchElementOffset) - m_foundObjectReference = objectReference(id->name->asString()); - } - } - } - } - } - - return true; -} - -QDeclarativeDebugObjectReference ScriptBindingParser::objectReferenceForScriptBinding(UiScriptBinding *binding) const -{ - return _idBindings.value(binding); -} - -// Delta - -static QString propertyName(UiQualifiedId *id) -{ - QString s; - - for (; id; id = id->next) { - if (! id->name) - return QString(); - - s += id->name->asString(); - - if (id->next) - s += QLatin1Char('.'); - } - - return s; -} - -QDeclarativeDebugObjectReference Delta::objectReferenceForUiObject(const ScriptBindingParser &bindingParser, UiObjectMember *object) -{ - if (UiScriptBinding *idBinding = bindingParser.id(object)) { - if (ExpressionStatement *s = cast<ExpressionStatement *>(idBinding->statement)) { - if (IdentifierExpression *idExpr = cast<IdentifierExpression *>(s->expression)) { - const QString idString = idExpr->name->asString(); - - const QList<QDeclarativeDebugObjectReference> refs = ClientProxy::instance()->objectReferences(_url); - foreach (const QDeclarativeDebugObjectReference &ref, refs) { - if (ref.idString() == idString) - return ref; - } - } - } - } - return QDeclarativeDebugObjectReference(); -} - - -void Delta::operator()(Document::Ptr doc, Document::Ptr previousDoc) -{ - _doc = doc; - _previousDoc = previousDoc; - _changes.clear(); - - _url = QUrl::fromLocalFile(doc->fileName()); - const QList<QDeclarativeDebugObjectReference> references = ClientProxy::instance()->objectReferences(_url); - - ScriptBindingParser bindingParser(doc, references); - bindingParser.process(); - - ScriptBindingParser previousBindingParser(previousDoc, references); - previousBindingParser.process(); - - QHash<UiObjectMember *, UiObjectMember *> preservedObjects; - - foreach (UiScriptBinding *id, bindingParser.ids()) { - UiObjectMember *parent = bindingParser.parent(id); - const QString idCode = bindingParser.scriptCode(id); - - foreach (UiScriptBinding *otherId, previousBindingParser.ids()) { - const QString otherIdCode = previousBindingParser.scriptCode(otherId); - - if (idCode == otherIdCode) { - preservedObjects.insert(parent, previousBindingParser.parent(otherId)); - } - } - } - - QHashIterator<UiObjectMember *, UiObjectMember *> it(preservedObjects); - while (it.hasNext()) { - it.next(); - - UiObjectMember *object = it.key(); - UiObjectMember *previousObject = it.value(); - - for (UiObjectMemberList *objectMemberIt = objectMembers(object); objectMemberIt; objectMemberIt = objectMemberIt->next) { - if (UiScriptBinding *script = cast<UiScriptBinding *>(objectMemberIt->member)) { - for (UiObjectMemberList *previousObjectMemberIt = objectMembers(previousObject); previousObjectMemberIt; previousObjectMemberIt = previousObjectMemberIt->next) { - if (UiScriptBinding *previousScript = cast<UiScriptBinding *>(previousObjectMemberIt->member)) { - if (compare(script->qualifiedId, previousScript->qualifiedId)) { - const QString scriptCode = bindingParser.scriptCode(script); - const QString previousScriptCode = previousBindingParser.scriptCode(previousScript); - - if (scriptCode != previousScriptCode) { - const QString property = propertyName(script->qualifiedId); - - QDeclarativeDebugObjectReference ref = objectReferenceForUiObject(bindingParser, object); - if (ref.debugId() != -1) - updateScriptBinding(ref, script, property, scriptCode); - } - } - } - } - } else if (UiSourceElement *uiSource = cast<UiSourceElement*>(objectMemberIt->member)) { - - for (UiObjectMemberList *previousObjectMemberIt = objectMembers(previousObject); - previousObjectMemberIt; previousObjectMemberIt = previousObjectMemberIt->next) - { - if (UiSourceElement *previousSource = cast<UiSourceElement*>(previousObjectMemberIt->member)) { - if (compare(uiSource, previousSource)) - { - const QString methodCode = bindingParser.methodCode(uiSource); - const QString previousMethodCode = previousBindingParser.methodCode(previousSource); - - if (methodCode != previousMethodCode) { - const QString methodName = bindingParser.methodName(uiSource); - QDeclarativeDebugObjectReference ref = objectReferenceForUiObject(bindingParser, object); - if (ref.debugId() != -1) - updateMethodBody(ref, script, methodName, methodCode); - } - } - } - } - - } - } - - } -} - void Delta::updateMethodBody(const QDeclarativeDebugObjectReference &objectReference, UiScriptBinding *scriptBinding, const QString &methodName, diff --git a/src/plugins/qmljsinspector/qmljsdelta.h b/src/plugins/qmljsinspector/qmljsdelta.h index 6d462bced79cf34c4655dcc5d6a1ca5f77a1ec04..30f06fce93c5bf3236e83c8477aca19a96cd49e2 100644 --- a/src/plugins/qmljsinspector/qmljsdelta.h +++ b/src/plugins/qmljsinspector/qmljsdelta.h @@ -43,53 +43,6 @@ using namespace QmlJS::AST; namespace QmlJSInspector { namespace Internal { -class ScriptBindingParser : protected Visitor -{ -public: - QmlJS::Document::Ptr doc; - QList<UiScriptBinding *> scripts; - - ScriptBindingParser(Document::Ptr doc, - const QList<QDeclarativeDebugObjectReference> &objectReferences = QList<QDeclarativeDebugObjectReference>()); - void process(); - - UiObjectMember *parent(UiScriptBinding *script) const; - UiScriptBinding *id(UiObjectMember *parent) const; - QList<UiScriptBinding *> ids() const; - - QDeclarativeDebugObjectReference objectReferenceForPosition(const QUrl &url, int line, int col) const; - - QDeclarativeDebugObjectReference objectReferenceForScriptBinding(UiScriptBinding *binding) const; - - QDeclarativeDebugObjectReference objectReferenceForOffset(unsigned int offset); - - QString header(UiObjectMember *member) const; - - QString scriptCode(UiScriptBinding *script) const; - QString methodName(UiSourceElement *source) const; - QString methodCode(UiSourceElement *source) const; - -protected: - QDeclarativeDebugObjectReference objectReference(const QString &id) const; - - virtual bool visit(UiObjectDefinition *ast); - virtual void endVisit(UiObjectDefinition *); - virtual bool visit(UiObjectBinding *ast); - virtual void endVisit(UiObjectBinding *); - virtual bool visit(UiScriptBinding *ast); - -private: - QList<UiObjectMember *> objectStack; - QHash<UiScriptBinding *, UiObjectMember *> _parent; - QHash<UiObjectMember *, UiScriptBinding *> _id; - QHash<UiScriptBinding *, QDeclarativeDebugObjectReference> _idBindings; - - QList<QDeclarativeDebugObjectReference> objectReferences; - QDeclarativeDebugObjectReference m_foundObjectReference; - unsigned int m_searchElementOffset; -}; - - class Delta { public: @@ -102,14 +55,15 @@ public: }; public: - void operator()(QmlJS::Document::Ptr doc, QmlJS::Document::Ptr previousDoc); + typedef QHash< UiObjectMember*, QList<QDeclarativeDebugObjectReference > > DebugIdMap; + DebugIdMap operator()(Document::Ptr doc1, Document::Ptr doc2, const DebugIdMap& debugIds); QList<Change> changes() const; QmlJS::Document::Ptr document() const; QmlJS::Document::Ptr previousDocument() const; -private: +public: void updateScriptBinding(const QDeclarativeDebugObjectReference &objectReference, QmlJS::AST::UiScriptBinding *scriptBinding, const QString &propertyName, @@ -119,10 +73,9 @@ private: const QString &methodName, const QString &methodBody); - bool compare(UiSourceElement *source, UiSourceElement *other); - bool compare(QmlJS::AST::UiQualifiedId *id, QmlJS::AST::UiQualifiedId *other); - QmlJS::AST::UiObjectMemberList *objectMembers(QmlJS::AST::UiObjectMember *object); - QDeclarativeDebugObjectReference objectReferenceForUiObject(const ScriptBindingParser &bindingParser, UiObjectMember *object); + static bool compare(UiSourceElement *source, UiSourceElement *other); + static bool compare(QmlJS::AST::UiQualifiedId *id, QmlJS::AST::UiQualifiedId *other); + static QmlJS::AST::UiObjectMemberList *objectMembers(QmlJS::AST::UiObjectMember *object); private: QmlJS::Document::Ptr _doc; diff --git a/src/plugins/qmljsinspector/qmljsinspector.cpp b/src/plugins/qmljsinspector/qmljsinspector.cpp index b26df17f53f15da35c8d12ae234fca3088f0f9d5..57aed3284a044a65fa326ba66b876487d61d05dd 100644 --- a/src/plugins/qmljsinspector/qmljsinspector.cpp +++ b/src/plugins/qmljsinspector/qmljsinspector.cpp @@ -101,6 +101,11 @@ using namespace QmlJS::AST; using namespace QmlJSInspector::Internal; using namespace Debugger::Internal; + + + + + enum { MaxConnectionAttempts = 50, ConnectionAttemptDefaultInterval = 75, @@ -138,6 +143,7 @@ Inspector::Inspector(QObject *parent) connect(m_clientProxy, SIGNAL(aboutToReloadEngines()), SLOT(aboutToReloadEngines())); connect(m_clientProxy, SIGNAL(enginesChanged()), SLOT(updateEngineList())); connect(m_clientProxy, SIGNAL(aboutToDisconnect()), SLOT(disconnectWidgets())); + connect(m_clientProxy, SIGNAL(objectTreeUpdated(QDeclarativeDebugObjectReference)),SLOT(objectTreeUpdated(QDeclarativeDebugObjectReference))); connect(Debugger::DebuggerPlugin::instance(), SIGNAL(stateChanged(int)), this, SLOT(debuggerStateChanged(int))); @@ -145,6 +151,7 @@ Inspector::Inspector(QObject *parent) connect(m_connectionTimer, SIGNAL(timeout()), SLOT(pollInspector())); } + Inspector::~Inspector() { } @@ -562,3 +569,68 @@ bool Inspector::addQuotesForData(const QVariant &value) const return false; } + +/*! + Associates the UiObjectMember* to their QDeclarativeDebugObjectReference. + */ +class MapObjectWithDebugReference : public Visitor +{ + public: + virtual void endVisit(UiObjectDefinition *ast) ; + virtual void endVisit(UiObjectBinding *ast) ; + + QDeclarativeDebugObjectReference root; + QString filename; + QHash<UiObjectMember *, QList<QDeclarativeDebugObjectReference> > result; + private: + void processRecursive(const QDeclarativeDebugObjectReference &object, UiObjectMember *ast); +}; + +void MapObjectWithDebugReference::endVisit(UiObjectDefinition* ast) +{ + if (ast->qualifiedTypeNameId->name->asString().at(0).isUpper()) + processRecursive(root, ast); +} +void MapObjectWithDebugReference::endVisit(UiObjectBinding* ast) +{ + if (ast->qualifiedId->name->asString().at(0).isUpper()) + processRecursive(root, ast); +} + +void MapObjectWithDebugReference::processRecursive(const QDeclarativeDebugObjectReference& object, UiObjectMember* ast) +{ + // If this is too slow, it can be speed up by indexing + // the QDeclarativeDebugObjectReference by filename/loc in a fist pass + + SourceLocation loc = ast->firstSourceLocation(); + if (object.source().lineNumber() == int(loc.startLine) && object.source().url().toLocalFile() == filename) { + result[ast] += object; + } + + foreach (const QDeclarativeDebugObjectReference &it, object.children()) { + processRecursive(it, ast); + } +} + +void QmlJSInspector::Internal::Inspector::objectTreeUpdated(const QDeclarativeDebugObjectReference &ref) +{ + QmlJS::ModelManagerInterface *m = QmlJS::ModelManagerInterface::instance(); + Snapshot snapshot = m->snapshot(); + QHash<QString, QHash<UiObjectMember *, QList< QDeclarativeDebugObjectReference> > > allDebugIds; + foreach(const Document::Ptr &doc, snapshot) { + if (!doc->qmlProgram()) + continue; + MapObjectWithDebugReference visitor; + visitor.root = ref; + QString filename = doc->fileName(); + visitor.filename = filename; + doc->qmlProgram()->accept(&visitor); + allDebugIds[filename] = visitor.result; + } + + //FIXME + m_textPreview->m_initialTable = allDebugIds; + m_textPreview->m_debugIds.clear(); +} + + diff --git a/src/plugins/qmljsinspector/qmljsinspector.h b/src/plugins/qmljsinspector/qmljsinspector.h index 228011280be7b639692cdf4c5dec538eaa595f74..ac8de8f6362fd185ee62b14ddcb586c505aa94a3 100644 --- a/src/plugins/qmljsinspector/qmljsinspector.h +++ b/src/plugins/qmljsinspector/qmljsinspector.h @@ -72,6 +72,8 @@ public: QmlProjectWithCppPlugins }; + QHash< QString, QList< QPair< QmlJS::AST::UiObjectMember*, int > > > m_initialTable; + public: Inspector(QObject *parent = 0); virtual ~Inspector(); @@ -115,6 +117,8 @@ private slots: void disconnectWidgets(); void disconnected(); + void objectTreeUpdated(const QDeclarativeDebugObjectReference &ref); + private: Debugger::DebuggerRunControl *createDebuggerRunControl(ProjectExplorer::RunConfiguration *runConfig, const QString &executableFile = QString(), diff --git a/src/plugins/qmljsinspector/qmljslivetextpreview.cpp b/src/plugins/qmljsinspector/qmljslivetextpreview.cpp index 9cce2ea13d925cd4885d348a8256dd59ceaafe39..0dd55e22451809fdb3bbe2fe165d347434b01b8e 100644 --- a/src/plugins/qmljsinspector/qmljslivetextpreview.cpp +++ b/src/plugins/qmljsinspector/qmljslivetextpreview.cpp @@ -60,7 +60,7 @@ void QmlJSLiveTextPreview::changeSelectedElement(int offset, const QString &word ClientProxy *clientProxy = ClientProxy::instance(); QUrl url = QUrl::fromLocalFile(m_currentEditor.data()->file()->fileName()); QmlJS::Document::Ptr doc = modelManager()->snapshot().document(m_currentEditor.data()->file()->fileName()); - ScriptBindingParser info(doc, clientProxy->objectReferences(url)); + //ScriptBindingParser info(doc, clientProxy->objectReferences(url)); QDeclarativeDebugObjectReference objectRef; @@ -72,9 +72,10 @@ void QmlJSLiveTextPreview::changeSelectedElement(int offset, const QString &word } } + /* FIXME if (objectRef.debugId() == -1 && offset >= 0) { objectRef = info.objectReferenceForOffset(offset); - } + }*/ if (objectRef.debugId() != -1) emit selectedItemsChanged(QList<QDeclarativeDebugObjectReference>() << objectRef); @@ -96,20 +97,28 @@ void QmlJSLiveTextPreview::setEditor(Core::IEditor *editor) } } + void QmlJSLiveTextPreview::documentChanged(QmlJS::Document::Ptr doc) -{ +{ + /* FIXME Core::ICore *core = Core::ICore::instance(); const int dbgcontext = core->uniqueIDManager()->uniqueIdentifier(Debugger::Constants::C_DEBUGMODE); if (!core->hasContext(dbgcontext)) return; + */ if (doc && m_previousDoc && doc->fileName() == m_previousDoc->fileName()) { + + if (m_debugIds.isEmpty()) + m_debugIds = m_initialTable.value(doc->fileName()); Delta delta; - delta(doc, m_previousDoc); + m_debugIds = delta(m_previousDoc, doc, m_debugIds); m_previousDoc = doc; + } } + } // namespace Internal } // namespace QmlJSInspector diff --git a/src/plugins/qmljsinspector/qmljslivetextpreview.h b/src/plugins/qmljsinspector/qmljslivetextpreview.h index 6b22721b2676a30abfea98bd4e968c18c9789bc9..a843c914b9ccffadf01ff6c70520086612c3bac6 100644 --- a/src/plugins/qmljsinspector/qmljslivetextpreview.h +++ b/src/plugins/qmljsinspector/qmljslivetextpreview.h @@ -31,6 +31,7 @@ namespace Internal { class QmlJSLiveTextPreview : public QObject { Q_OBJECT + public: explicit QmlJSLiveTextPreview(QObject *parent = 0); static QmlJS::ModelManagerInterface *modelManager(); @@ -39,6 +40,9 @@ public: void setActiveObject(const QDeclarativeDebugObjectReference &object); void mapObjectToQml(const QDeclarativeDebugObjectReference &object); + QHash<QString, QHash<QmlJS::AST::UiObjectMember *, QList< QDeclarativeDebugObjectReference> > > m_initialTable; + QHash< QmlJS::AST::UiObjectMember*, QList<QDeclarativeDebugObjectReference > > m_debugIds; + signals: void selectedItemsChanged(const QList<QDeclarativeDebugObjectReference> &objects);