diff --git a/src/plugins/duieditor/duidocument.cpp b/src/plugins/duieditor/duidocument.cpp
index 9d13d4745cdca77fa51cdfa0196a9b2337ce3711..02680b08f5b43098a42faa10e474dce65b063adb 100644
--- a/src/plugins/duieditor/duidocument.cpp
+++ b/src/plugins/duieditor/duidocument.cpp
@@ -27,6 +27,7 @@
 **
 **************************************************************************/
 
+#include "idcollector.h"
 #include "duidocument.h"
 #include "qmljsast_p.h"
 #include "qmljslexer_p.h"
@@ -44,12 +45,21 @@ DuiDocument::DuiDocument(const QString &fileName)
     , _fileName(fileName)
     , _parsedCorrectly(false)
 {
+    const int slashIdx = fileName.lastIndexOf('/');
+    if (slashIdx != -1)
+        _path = fileName.left(slashIdx);
+
+    if (fileName.toLower().endsWith(".qml"))
+        _componentName = fileName.mid(slashIdx + 1, fileName.size() - (slashIdx + 1) - 4);
 }
 
 DuiDocument::~DuiDocument()
 {
-    delete _engine;
-    delete _pool;
+    if (_engine)
+        delete _engine;
+
+    if (_pool)
+        delete _pool;
 }
 
 DuiDocument::Ptr DuiDocument::create(const QString &fileName)
@@ -81,6 +91,7 @@ bool DuiDocument::parse()
 
     _engine = new Engine();
     _pool = new NodePool(_fileName, _engine);
+    _ids.clear();
 
     Lexer lexer(_engine);
     Parser parser(_engine);
@@ -90,6 +101,12 @@ bool DuiDocument::parse()
     _parsedCorrectly = parser.parse();
     _program = parser.ast();
     _diagnosticMessages = parser.diagnosticMessages();
+
+    if (_parsedCorrectly && _program) {
+        Internal::IdCollector collect;
+        _ids = collect(_program);
+    }
+
     return _parsedCorrectly;
 }
 
@@ -100,3 +117,46 @@ Snapshot::Snapshot()
 Snapshot::~Snapshot()
 {
 }
+
+void Snapshot::insert(const DuiDocument::Ptr &document)
+{
+    QMap<QString, DuiDocument::Ptr>::insert(document->fileName(), document);
+}
+
+DuiDocument::PtrList Snapshot::importedDocuments(const DuiDocument::Ptr &doc, const QString &importPath)
+{
+    DuiDocument::PtrList result;
+
+    const QString docPath = doc->path() + '/' + importPath;
+
+    for (Iterator i = iterator(); i.hasNext();) {
+        DuiDocument::Ptr candidate = i.next().value();
+
+        if (candidate == doc)
+            continue;
+
+        if (candidate->path() == doc->path() || candidate->path() == docPath)
+            result.append(candidate);
+    }
+
+    return result;
+}
+
+QMap<QString, DuiDocument::Ptr> Snapshot::componentsDefinedByImportedDocuments(const DuiDocument::Ptr &doc, const QString &importPath)
+{
+    QMap<QString, DuiDocument::Ptr> result;
+
+    const QString docPath = doc->path() + '/' + importPath;
+
+    for (Iterator i = iterator(); i.hasNext();) {
+        DuiDocument::Ptr candidate = i.next().value();
+
+        if (candidate == doc)
+            continue;
+
+        if (candidate->path() == doc->path() || candidate->path() == docPath)
+            result.insert(candidate->componentName(), candidate);
+    }
+
+    return result;
+}
diff --git a/src/plugins/duieditor/duidocument.h b/src/plugins/duieditor/duidocument.h
index f1ad2a8471d6bc130b025dffa61f1903e6677dd9..dd99c97ab2df751d4ed80607394e0237590c6a0a 100644
--- a/src/plugins/duieditor/duidocument.h
+++ b/src/plugins/duieditor/duidocument.h
@@ -29,8 +29,10 @@
 #ifndef DUIDOCUMENT_H
 #define DUIDOCUMENT_H
 
-#include <QtCore/QSharedPointer>
+#include <QtCore/QList>
 #include <QtCore/QMap>
+#include <QtCore/QPair>
+#include <QtCore/QSharedPointer>
 #include <QtCore/QString>
 
 #include "duieditor_global.h"
@@ -44,6 +46,8 @@ class DUIEDITOR_EXPORT DuiDocument
 {
 public:
 	typedef QSharedPointer<DuiDocument> Ptr;
+    typedef QList<DuiDocument::Ptr> PtrList;
+    typedef QMap<QString, QPair<QmlJS::AST::SourceLocation, QmlJS::AST::Node*> > IdTable;
 
 protected:
 	DuiDocument(const QString &fileName);
@@ -62,7 +66,11 @@ public:
     bool isParsedCorrectly() const
     { return _parsedCorrectly; }
 
+    IdTable ids() const { return _ids; }
+
     QString fileName() const { return _fileName; }
+    QString path() const { return _path; }
+    QString componentName() const { return _componentName; }
 
 private:
 	QmlJS::Engine *_engine;
@@ -70,8 +78,11 @@ private:
 	QmlJS::AST::UiProgram *_program;
 	QList<QmlJS::DiagnosticMessage> _diagnosticMessages;
 	QString _fileName;
+    QString _path;
+    QString _componentName;
 	QString _source;
     bool _parsedCorrectly;
+    IdTable _ids;
 };
 
 class DUIEDITOR_EXPORT Snapshot: protected QMap<QString, DuiDocument::Ptr>
@@ -80,8 +91,7 @@ public:
 	Snapshot();
 	~Snapshot();
 
-    void insert(const DuiDocument::Ptr &document)
-    { QMap<QString, DuiDocument::Ptr>::insert(document->fileName(), document); }
+    void insert(const DuiDocument::Ptr &document);
 
     typedef QMapIterator<QString, DuiDocument::Ptr> Iterator;
     Iterator iterator() const
@@ -89,6 +99,9 @@ public:
 
     DuiDocument::Ptr document(const QString &fileName) const
     { return value(fileName); }
+
+    DuiDocument::PtrList importedDocuments(const DuiDocument::Ptr &doc, const QString &importPath);
+    QMap<QString, DuiDocument::Ptr> componentsDefinedByImportedDocuments(const DuiDocument::Ptr &doc, const QString &importPath);
 };
 
 } // emd of namespace DuiEditor
diff --git a/src/plugins/duieditor/duieditor.cpp b/src/plugins/duieditor/duieditor.cpp
index e3820817879edc0ca3103247eff76a243bc61744..3add88f8de76bacfcc5479faf873211fa926ac26 100644
--- a/src/plugins/duieditor/duieditor.cpp
+++ b/src/plugins/duieditor/duieditor.cpp
@@ -714,11 +714,10 @@ TextEditor::BaseTextEditor::Link ScriptEditor::findLinkAt(const QTextCursor &cur
     if (!doc)
         return link;
 
-    QMap<QString, QmlJS::AST::SourceLocation> idPositions = IdCollector()(doc->program());
-
     NavigationTokenFinder finder;
-    if (finder(doc->program(), cursor.position(), resolveTarget, idPositions)) {
-        link.fileName = file()->fileName();
+    finder(doc, cursor.position(), snapshot);
+    if (finder.targetFound()) {
+        link.fileName = finder.fileName();
         link.pos = finder.linkPosition();
         link.length = finder.linkLength();
 
diff --git a/src/plugins/duieditor/duimodelmanager.cpp b/src/plugins/duieditor/duimodelmanager.cpp
index 6af277514a4c0931f258756c31738d10148d617e..5645c8cc424e5fed5bccabf8285c3fe26fcde968 100644
--- a/src/plugins/duieditor/duimodelmanager.cpp
+++ b/src/plugins/duieditor/duimodelmanager.cpp
@@ -69,34 +69,36 @@ void DuiModelManager::updateSourceFiles(const QStringList &files)
 
 QFuture<void> DuiModelManager::refreshSourceFiles(const QStringList &sourceFiles)
 {
-    if (! sourceFiles.isEmpty()) {
-        const QMap<QString, QString> workingCopy = buildWorkingCopyList();
+    if (sourceFiles.isEmpty()) {
+        return QFuture<void>();
+    }
 
-        QFuture<void> result = QtConcurrent::run(&DuiModelManager::parse,
-                                                 workingCopy, sourceFiles,
-                                                 this);
+    const QMap<QString, QString> workingCopy = buildWorkingCopyList();
 
-        if (m_synchronizer.futures().size() > 10) {
-            QList<QFuture<void> > futures = m_synchronizer.futures();
+    QFuture<void> result = QtConcurrent::run(&DuiModelManager::parse,
+                                              workingCopy, sourceFiles,
+                                              this);
 
-            m_synchronizer.clearFutures();
+    if (m_synchronizer.futures().size() > 10) {
+        QList<QFuture<void> > futures = m_synchronizer.futures();
 
-            foreach (QFuture<void> future, futures) {
-                if (! (future.isFinished() || future.isCanceled()))
-                    m_synchronizer.addFuture(future);
-            }
+        m_synchronizer.clearFutures();
+
+        foreach (QFuture<void> future, futures) {
+            if (! (future.isFinished() || future.isCanceled()))
+                m_synchronizer.addFuture(future);
         }
+    }
 
-        m_synchronizer.addFuture(result);
+    m_synchronizer.addFuture(result);
 
-        if (sourceFiles.count() > 1) {
-            m_core->progressManager()->addTask(result, tr("Indexing"),
-                            DuiEditor::Constants::TASK_INDEX,
-                            Core::ProgressManager::CloseOnSuccess);
-        }
-        return result;
+    if (sourceFiles.count() > 1) {
+        m_core->progressManager()->addTask(result, tr("Indexing"),
+                        DuiEditor::Constants::TASK_INDEX,
+                        Core::ProgressManager::CloseOnSuccess);
     }
-    return QFuture<void>();
+
+    return result;
 }
 
 QMap<QString, QString> DuiModelManager::buildWorkingCopyList()
diff --git a/src/plugins/duieditor/idcollector.cpp b/src/plugins/duieditor/idcollector.cpp
index 3597a752d0b5855588e7ec3f63cfcf8d4bd0c1d5..97536aa7193fcbbea3aa8d34526df9972ad313cb 100644
--- a/src/plugins/duieditor/idcollector.cpp
+++ b/src/plugins/duieditor/idcollector.cpp
@@ -6,13 +6,35 @@ using namespace QmlJS;
 using namespace QmlJS::AST;
 using namespace DuiEditor::Internal;
 
-QMap<QString, QmlJS::AST::SourceLocation> IdCollector::operator()(QmlJS::AST::UiProgram *ast)
+QMap<QString, QPair<QmlJS::AST::SourceLocation, QmlJS::AST::Node*> > IdCollector::operator()(QmlJS::AST::UiProgram *ast)
 {
-    _idLocations.clear();
+    _ids.clear();
 
     Node::accept(ast, this);
 
-    return _idLocations;
+    return _ids;
+}
+
+bool IdCollector::visit(QmlJS::AST::UiObjectBinding *ast)
+{
+    _scopes.push(ast);
+    return true;
+}
+
+bool IdCollector::visit(QmlJS::AST::UiObjectDefinition *ast)
+{
+    _scopes.push(ast);
+    return true;
+}
+
+void IdCollector::endVisit(QmlJS::AST::UiObjectBinding *)
+{
+    _scopes.pop();
+}
+
+void IdCollector::endVisit(QmlJS::AST::UiObjectDefinition *)
+{
+    _scopes.pop();
 }
 
 bool IdCollector::visit(QmlJS::AST::UiScriptBinding *ast)
@@ -29,6 +51,6 @@ void IdCollector::addId(QmlJS::NameId* id, const QmlJS::AST::SourceLocation &idL
 {
     const QString idString = id->asString();
 
-    if (!_idLocations.contains(idString))
-        _idLocations[idString] = idLocation;
+    if (!_ids.contains(idString))
+        _ids[idString] = qMakePair(idLocation, _scopes.top());
 }
diff --git a/src/plugins/duieditor/idcollector.h b/src/plugins/duieditor/idcollector.h
index ac10b9c1e47b9e37130ae1c3cc8486032e5a32af..91e2a1fed86bde082d0ccad59fc1788aa6bdaeda 100644
--- a/src/plugins/duieditor/idcollector.h
+++ b/src/plugins/duieditor/idcollector.h
@@ -2,6 +2,8 @@
 #define IDCOLLECTOR_H
 
 #include <QMap>
+#include <QPair>
+#include <QStack>
 #include <QString>
 
 #include "qmljsastvisitor_p.h"
@@ -14,16 +16,22 @@ namespace Internal {
 class IdCollector: protected QmlJS::AST::Visitor
 {
 public:
-    QMap<QString, QmlJS::AST::SourceLocation> operator()(QmlJS::AST::UiProgram *ast);
+    QMap<QString, QPair<QmlJS::AST::SourceLocation, QmlJS::AST::Node*> > operator()(QmlJS::AST::UiProgram *ast);
 
 protected:
+    virtual bool visit(QmlJS::AST::UiObjectBinding *ast);
+    virtual bool visit(QmlJS::AST::UiObjectDefinition *ast);
     virtual bool visit(QmlJS::AST::UiScriptBinding *ast);
 
+    virtual void endVisit(QmlJS::AST::UiObjectBinding *);
+    virtual void endVisit(QmlJS::AST::UiObjectDefinition *);
+
 private:
     void addId(QmlJS::NameId* id, const QmlJS::AST::SourceLocation &idLocation);
 
 private:
-    QMap<QString, QmlJS::AST::SourceLocation> _idLocations;
+    QMap<QString, QPair<QmlJS::AST::SourceLocation, QmlJS::AST::Node*> > _ids;
+    QStack<QmlJS::AST::Node *> _scopes;
 };
 
 } // namespace Internal
diff --git a/src/plugins/duieditor/navigationtokenfinder.cpp b/src/plugins/duieditor/navigationtokenfinder.cpp
index ea007c95349d699bfcec425c085ae678b4cf1907..0dda0f8e372d76ecba896e875664e09b912a33ee 100644
--- a/src/plugins/duieditor/navigationtokenfinder.cpp
+++ b/src/plugins/duieditor/navigationtokenfinder.cpp
@@ -5,23 +5,60 @@
 
 using namespace QmlJS;
 using namespace QmlJS::AST;
+using namespace DuiEditor;
 using namespace DuiEditor::Internal;
 
-bool NavigationTokenFinder::operator()(QmlJS::AST::UiProgram *ast, int position, bool resolveTarget, const QMap<QString, QmlJS::AST::SourceLocation> &idPositions)
+void NavigationTokenFinder::operator()(const DuiDocument::Ptr &doc, int position, const Snapshot &snapshot)
 {
-    _resolveTarget = resolveTarget;
+    _doc = doc;
+    _snapshot = snapshot;
     _pos = position;
-    _idPositions = idPositions;
     _scopes.clear();
     _linkPosition = -1;
+    _fileName.clear();
     _targetLine = -1;
 
-    Node::accept(ast, this);
+    Node::accept(doc->program(), this);
+}
+
+static QStringList buildQualifiedId(QmlJS::AST::FieldMemberExpression *expr)
+{
+    QStringList qId;
+
+    if (FieldMemberExpression *baseExpr = cast<FieldMemberExpression*>(expr->base)) {
+        qId = buildQualifiedId(baseExpr);
+    } else if (IdentifierExpression *idExpr = cast<IdentifierExpression*>(expr->base)) {
+        qId.append(idExpr->name->asString());
+    } else {
+        return qId;
+    }
 
-    if (resolveTarget)
-        return targetFound();
-    else
-        return linkFound();
+    qId.append(expr->name->asString());
+    return qId;
+}
+
+bool NavigationTokenFinder::visit(QmlJS::AST::FieldMemberExpression *ast)
+{
+    if (linkFound())
+        return false;
+
+    if (ast->firstSourceLocation().offset <= _pos && _pos <= ast->lastSourceLocation().end()) {
+        if (ast->identifierToken.offset <= _pos && _pos <= ast->identifierToken.end()) {
+            // found it:
+            _linkPosition = ast->identifierToken.offset;
+            _linkLength = ast->identifierToken.end() - _linkPosition;
+
+            const QStringList qualifiedId(buildQualifiedId(ast));
+            if (!qualifiedId.isEmpty())
+                findDeclaration(qualifiedId);
+        } else {
+            Node::accept(ast->base, this);
+        }
+
+        return false;
+    }
+
+    return true;
 }
 
 bool NavigationTokenFinder::visit(QmlJS::AST::IdentifierExpression *ast)
@@ -33,8 +70,7 @@ bool NavigationTokenFinder::visit(QmlJS::AST::IdentifierExpression *ast)
         _linkPosition = ast->identifierToken.offset;
         _linkLength = ast->identifierToken.length;
 
-        if (Node *node = findDeclarationInScopesOrIds(ast->name))
-            rememberStartPosition(node);
+        findDeclaration(QStringList() << ast->name->asString());
     }
 
     return false;
@@ -50,6 +86,11 @@ bool NavigationTokenFinder::visit(QmlJS::AST::UiArrayBinding *ast)
     return false;
 }
 
+bool NavigationTokenFinder::visit(QmlJS::AST::UiImportList *)
+{
+    return false;
+}
+
 bool NavigationTokenFinder::visit(QmlJS::AST::UiPublicMember *ast)
 {
     if (linkFound())
@@ -64,10 +105,7 @@ bool NavigationTokenFinder::visit(QmlJS::AST::Block *ast)
 {
     _scopes.push(ast);
 
-    if (linkFound())
-        return false;
-
-    return true;
+    return !linkFound();
 }
 
 void NavigationTokenFinder::endVisit(QmlJS::AST::Block *)
@@ -79,11 +117,10 @@ bool NavigationTokenFinder::visit(QmlJS::AST::UiObjectBinding *ast)
 {
     _scopes.push(ast);
 
-    if (linkFound())
-        return false;
-
-    Node::accept(ast->qualifiedTypeNameId, this);
-    Node::accept(ast->initializer, this);
+    if (!linkFound()) {
+        checkType(ast->qualifiedTypeNameId);
+        Node::accept(ast->initializer, this);
+    }
 
     return false;
 }
@@ -97,10 +134,12 @@ bool NavigationTokenFinder::visit(QmlJS::AST::UiObjectDefinition *ast)
 {
     _scopes.push(ast);
 
-    if (linkFound())
-        return false;
+    if (!linkFound()) {
+        checkType(ast->qualifiedTypeNameId);
+        Node::accept(ast->initializer, this);
+    }
 
-    return true;
+    return false;
 }
 
 void NavigationTokenFinder::endVisit(QmlJS::AST::UiObjectDefinition *)
@@ -108,36 +147,34 @@ void NavigationTokenFinder::endVisit(QmlJS::AST::UiObjectDefinition *)
     _scopes.pop();
 }
 
-bool NavigationTokenFinder::visit(QmlJS::AST::UiQualifiedId *ast)
+void NavigationTokenFinder::checkType(QmlJS::AST::UiQualifiedId *ast)
 {
-    if (linkFound())
-        return false;
-
     if (ast->identifierToken.offset <= _pos) {
         for (UiQualifiedId *iter = ast; iter; iter = iter->next) {
             if (_pos <= iter->identifierToken.end()) {
                 _linkPosition = ast->identifierToken.offset;
 
-                for (UiQualifiedId *iter2 = ast; iter2; iter2 = iter2->next)
+                QStringList names;
+                for (UiQualifiedId *iter2 = ast; iter2; iter2 = iter2->next) {
                     _linkLength = iter2->identifierToken.end() - _linkPosition;
+                    names.append(iter2->name->asString());
+                }
+                findTypeDeclaration(names);
 
-                if (Node *node = findDeclarationInScopesOrIds(ast))
-                    rememberStartPosition(node);
-
-                return false;
+                return;
             }
         }
     }
-
-    return false;
 }
 
 bool NavigationTokenFinder::visit(QmlJS::AST::UiScriptBinding *ast)
 {
-    if (linkFound())
-        return false;
-
-    Node::accept(ast->statement, this);
+    if (!linkFound()) {
+        if (ast->qualifiedId && !ast->qualifiedId->next && ast->qualifiedId->name && ast->qualifiedId->name->asString() == "id")
+            return false;
+        else
+            Node::accept(ast->statement, this);
+    }
 
     return false;
 }
@@ -147,134 +184,172 @@ bool NavigationTokenFinder::visit(QmlJS::AST::UiSourceElement * /*ast*/)
     return false;
 }
 
-void NavigationTokenFinder::rememberStartPosition(QmlJS::AST::Node *node)
+bool NavigationTokenFinder::findInJS(const QStringList &qualifiedId, QmlJS::AST::Block *block)
 {
-    if (UiObjectMember *om = dynamic_cast<UiObjectMember*>(node)) {
-        _targetLine = om->firstSourceLocation().startLine;
-        _targetColumn = om->firstSourceLocation().startColumn;
-    } else if (VariableDeclaration *vd = cast<VariableDeclaration*>(node)) {
-        _targetLine = vd->identifierToken.startLine;
-        _targetColumn = vd->identifierToken.startColumn;
-    } else {
-//        qWarning() << "Found declaration of unknown type as a navigation target";
-    }
-}
+    if (qualifiedId.size() > 1)
+        return false; // we can only find "simple" JavaScript variables this way
 
-void NavigationTokenFinder::rememberStartPosition(const QmlJS::AST::SourceLocation &location)
-{
-    _targetLine = location.startLine;
-    _targetColumn = location.startColumn;
-}
+    const QString id = qualifiedId[0];
 
-static QmlJS::AST::Node *findDeclaration(const QString &nameId, QmlJS::AST::UiObjectMember *m)
-{
-    if (UiPublicMember *p = cast<UiPublicMember*>(m)) {
-        if (p->name->asString() == nameId)
-            return p;
-    } else if (UiObjectBinding *o = cast<UiObjectBinding*>(m)) {
-        if (!(o->qualifiedId->next) && o->qualifiedId->name->asString() == nameId)
-            return o;
-    } else if (UiArrayBinding *a = cast<UiArrayBinding*>(m)) {
-        if (!(a->qualifiedId->next) && a->qualifiedId->name->asString() == nameId)
-            return a;
+    for (StatementList *iter = block->statements; iter; iter = iter->next) {
+        Statement *stmt = iter->statement;
+
+        if (VariableStatement *varStmt = cast<VariableStatement*>(stmt)) {
+            for (VariableDeclarationList *varIter = varStmt->declarations; varIter; varIter = varIter->next) {
+                if (varIter->declaration && varIter->declaration->name && varIter->declaration->name->asString() == id) {
+                    rememberLocation(varIter->declaration->identifierToken);
+                    return true;
+                }
+            }
+        }
     }
 
-    return 0;
+    return false;
 }
 
-static QmlJS::AST::Node *findDeclaration(const QString &nameId, QmlJS::AST::UiObjectMemberList *l)
+static bool matches(UiQualifiedId *candidate, const QStringList &wanted)
 {
-    for (UiObjectMemberList *iter = l; iter; iter = iter->next)
-        if (Node *n = findDeclaration(nameId, iter->member))
-            return n;
+    UiQualifiedId *iter = candidate;
+    for (int i = 0; i < wanted.size(); ++i) {
+        if (!iter)
+            return false;
+
+        if (iter->name->asString() != wanted[i])
+            return false;
+
+        iter = iter->next;
+    }
 
-    return 0;
+    return !iter;
 }
 
-static QmlJS::AST::Node *findDeclaration(const QString &nameId, QmlJS::AST::Statement *s)
+bool NavigationTokenFinder::findProperty(const QStringList &qualifiedId, QmlJS::AST::UiQualifiedId *typeId, QmlJS::AST::UiObjectMemberList *ast, int scopeLevel)
 {
-    if (VariableStatement *v = cast<VariableStatement*>(s)) {
-        for (VariableDeclarationList *l = v->declarations; l; l = l->next) {
-            if (l->declaration->name->asString() == nameId)
-                return l->declaration;
+    // 1. try the "overridden" properties:
+    for (UiObjectMemberList *iter = ast; iter; iter = iter->next) {
+        UiObjectMember *member = iter->member;
+
+        if (UiPublicMember *publicMember = cast<UiPublicMember*>(member)) {
+            if (publicMember->name && qualifiedId.size() == 1 && publicMember->name->asString() == qualifiedId.first()) {
+                rememberLocation(publicMember->identifierToken);
+                return true;
+            }
+        } else if (UiObjectBinding *objectBinding = cast<UiObjectBinding*>(member)) {
+            if (matches(objectBinding->qualifiedId, qualifiedId)) {
+                rememberLocation(objectBinding->qualifiedId->identifierToken);
+                return true;
+            }
+        } else if (UiScriptBinding *scriptBinding = cast<UiScriptBinding*>(member)) {
+            if (matches(scriptBinding->qualifiedId, qualifiedId)) {
+                rememberLocation(scriptBinding->qualifiedId->identifierToken);
+                return true;
+            }
+        } else if (UiArrayBinding *arrayBinding = cast<UiArrayBinding*>(member)) {
+            if (matches(arrayBinding->qualifiedId, qualifiedId)) {
+                rememberLocation(arrayBinding->qualifiedId->identifierToken);
+                return true;
+            }
         }
     }
 
-    return 0;
-}
+    // 2. if the property is "parent", go one scope level up:
+    if (qualifiedId[0] == "parent"){
+        if (scopeLevel <= 0)
+            return false;
+
+        int newScopeLevel = scopeLevel - 1;
+        Node *parentScope = _scopes[newScopeLevel];
+
+        QStringList newQualifiedId = qualifiedId;
+        newQualifiedId.removeFirst();
+        if (UiObjectBinding *binding = cast<UiObjectBinding*>(parentScope)) {
+            if (newQualifiedId.isEmpty()) {
+                rememberLocation(binding->qualifiedTypeNameId->identifierToken);
+                return true;
+            } else {
+                return findProperty(newQualifiedId, binding->qualifiedTypeNameId, binding->initializer->members, newScopeLevel);
+            }
+        } else if (UiObjectDefinition *definition = cast<UiObjectDefinition*>(parentScope)) {
+            if (newQualifiedId.isEmpty()) {
+                rememberLocation(definition->qualifiedTypeNameId->identifierToken);
+                return true;
+            } else {
+                return findProperty(newQualifiedId, definition->qualifiedTypeNameId, definition->initializer->members, newScopeLevel);
+            }
+        } else {
+            return false;
+        }
+    }
 
-static QmlJS::AST::Node *findDeclaration(const QString &nameId, QmlJS::AST::StatementList *l)
-{
-    for (StatementList *iter = l; iter; iter = iter->next)
-        if (Node *n = findDeclaration(nameId, iter->statement))
-            return n;
+    // 3. if the type is a custom type, search properties there:
+    {
+        // TODO
+    }
 
-    return 0;
+    // all failed, so:
+    return false;
 }
 
-static QmlJS::AST::Node *findDeclarationAsDirectChild(const QString &nameId, QmlJS::AST::Node *node)
+void NavigationTokenFinder::findAsId(const QStringList &qualifiedId)
 {
-    if (UiObjectBinding *binding = cast<UiObjectBinding*>(node)) {
-        return findDeclaration(nameId, binding->initializer->members);
-    } else if (UiObjectDefinition *def = cast<UiObjectDefinition*>(node)) {
-        return findDeclaration(nameId, def->initializer->members);
-    } else if (Block *block = cast<Block *>(node)) {
-        return findDeclaration(nameId, block->statements);
-    } else {
-        return 0;
+    const DuiDocument::IdTable ids = _doc->ids();
+
+    if (ids.contains(qualifiedId.first())) {
+        QPair<SourceLocation, Node*> idInfo = ids[qualifiedId.first()];
+        if (qualifiedId.size() == 1) {
+            rememberLocation(idInfo.first);
+        } else if (qualifiedId.size() == 2) {
+            Node *parent = idInfo.second;
+
+            if (UiObjectBinding *binding = cast<UiObjectBinding*>(parent)) {
+                findProperty(QStringList() << qualifiedId[1], binding->qualifiedTypeNameId, binding->initializer->members, -1);
+            } else if (UiObjectDefinition *definition = cast<UiObjectDefinition*>(parent)) {
+                findProperty(QStringList() << qualifiedId[1], definition->qualifiedTypeNameId, definition->initializer->members, -1);
+            }
+        }
     }
 }
 
-static QmlJS::AST::Node *findDeclarationInNode(QmlJS::AST::UiQualifiedId *qualifiedId, QmlJS::AST::Node *node)
+void NavigationTokenFinder::findDeclaration(const QStringList &qualifiedId, int scopeLevel)
 {
-    if (!qualifiedId || !node)
-        return node;
-    else
-        return findDeclarationInNode(qualifiedId->next, findDeclarationAsDirectChild(qualifiedId->name->asString(), node));
+    Node *scope = _scopes[scopeLevel];
+
+    if (Block *block = cast<Block*>(scope)) {
+        if (!findInJS(qualifiedId, block)) // continue searching the parent scope:
+            findDeclaration(qualifiedId, scopeLevel - 1);
+    } else if (UiObjectBinding *binding = cast<UiObjectBinding*>(scope)) {
+        if (findProperty(qualifiedId, binding->qualifiedTypeNameId, binding->initializer->members, scopeLevel)) {
+            return;
+        } else {
+            findAsId(qualifiedId);
+        }
+    } else if (UiObjectDefinition *definition = cast<UiObjectDefinition*>(scope)) {
+        if (findProperty(qualifiedId, definition->qualifiedTypeNameId, definition->initializer->members, scopeLevel)) {
+            return;
+        } else {
+            findAsId(qualifiedId);
+        }
+    } else {
+        Q_ASSERT(!"Unknown scope type");
+    }
 }
 
-QmlJS::AST::Node *NavigationTokenFinder::findDeclarationInScopesOrIds(QmlJS::NameId *nameId)
+void NavigationTokenFinder::findDeclaration(const QStringList &id)
 {
-    if (!_resolveTarget)
-        return 0;
-
-    const QString nameAsString = nameId->asString();
-    if (nameAsString == "parent" && _scopes.size() >= 2)
-        return _scopes.at(_scopes.size() - 2);
-
-    foreach (QmlJS::AST::Node *scope, _scopes) {
-        Node *result = findDeclarationAsDirectChild(nameAsString, scope);
-
-        if (result)
-            return result;
-    }
-
-    if (_idPositions.contains(nameAsString)) {
-        rememberStartPosition(_idPositions[nameAsString]);
-    }
+    if (id.isEmpty())
+        return;
 
-    return 0;
+    findDeclaration(id, _scopes.size() - 1);
 }
 
-QmlJS::AST::Node *NavigationTokenFinder::findDeclarationInScopesOrIds(QmlJS::AST::UiQualifiedId *qualifiedId)
+void NavigationTokenFinder::findTypeDeclaration(const QStringList &id)
 {
-    if (!_resolveTarget)
-        return 0;
-
-    const QString nameAsString = qualifiedId->name->asString();
-    if (nameAsString == "parent" && _scopes.size() >= 2)
-        return findDeclarationInNode(qualifiedId->next, _scopes.at(_scopes.size() - 2));
-
-    foreach (QmlJS::AST::Node *scope, _scopes) {
-        Node *result = findDeclarationAsDirectChild(nameAsString, scope);
-
-        if (result)
-            return findDeclarationInNode(qualifiedId->next, result);
-    }
-
-    if (_idPositions.contains(nameAsString)) {
-        rememberStartPosition(_idPositions[nameAsString]);
-    }
+    // TODO
+}
 
-    return 0;
+void NavigationTokenFinder::rememberLocation(const QmlJS::AST::SourceLocation &loc)
+{
+    _fileName = _doc->fileName();
+    _targetLine = loc.startLine;
+    _targetColumn = loc.startColumn;
 }
diff --git a/src/plugins/duieditor/navigationtokenfinder.h b/src/plugins/duieditor/navigationtokenfinder.h
index bcd8c73b46b7c3f0b24d02f2632550a070ab55e1..c05b4026148e94faa03cb5cbe648683099baefb7 100644
--- a/src/plugins/duieditor/navigationtokenfinder.h
+++ b/src/plugins/duieditor/navigationtokenfinder.h
@@ -4,7 +4,9 @@
 #include <QMap>
 #include <QStack>
 #include <QString>
+#include <QStringList>
 
+#include "duidocument.h"
 #include "qmljsastvisitor_p.h"
 
 namespace QmlJS {
@@ -17,24 +19,26 @@ namespace Internal {
 class NavigationTokenFinder: protected QmlJS::AST::Visitor
 {
 public:
-    bool operator()(QmlJS::AST::UiProgram *ast, int position, bool resolveTarget, const QMap<QString, QmlJS::AST::SourceLocation> &idPositions);
+    void operator()(const DuiDocument::Ptr &doc, int position, const Snapshot &snapshot);
 
     bool targetFound() const { return _targetLine != -1; }
     bool linkFound() const { return _linkPosition != -1; }
 
     int linkPosition() const { return _linkPosition; }
     int linkLength() const { return _linkLength; }
+    QString fileName() const { return _fileName; }
     int targetLine() const { return _targetLine; }
     int targetColumn() const { return _targetColumn; }
 
 protected:
     virtual bool visit(QmlJS::AST::Block *ast);
+    virtual bool visit(QmlJS::AST::FieldMemberExpression *ast);
     virtual bool visit(QmlJS::AST::IdentifierExpression *ast);
     virtual bool visit(QmlJS::AST::UiArrayBinding *ast);
+    virtual bool visit(QmlJS::AST::UiImportList *);
     virtual bool visit(QmlJS::AST::UiPublicMember *ast);
     virtual bool visit(QmlJS::AST::UiObjectBinding *ast);
     virtual bool visit(QmlJS::AST::UiObjectDefinition *ast);
-    virtual bool visit(QmlJS::AST::UiQualifiedId *ast);
     virtual bool visit(QmlJS::AST::UiScriptBinding *ast);
     virtual bool visit(QmlJS::AST::UiSourceElement *ast);
 
@@ -43,18 +47,22 @@ protected:
     virtual void endVisit(QmlJS::AST::UiObjectDefinition *);
 
 private:
-    QmlJS::AST::Node *findDeclarationInScopesOrIds(QmlJS::AST::UiQualifiedId *ast);
-    QmlJS::AST::Node *findDeclarationInScopesOrIds(QmlJS::NameId *id);
-
-    void rememberStartPosition(QmlJS::AST::Node *node);
-    void rememberStartPosition(const QmlJS::AST::SourceLocation &location);
+    void checkType(QmlJS::AST::UiQualifiedId *ast);
+    bool findInJS(const QStringList &qualifiedId, QmlJS::AST::Block *block);
+    bool findProperty(const QStringList &qualifiedId, QmlJS::AST::UiQualifiedId *typeId, QmlJS::AST::UiObjectMemberList *ast, int scopeLevel);
+    void findAsId(const QStringList &qualifiedId);
+    void findDeclaration(const QStringList &qualifiedId, int scopeLevel);
+    void findDeclaration(const QStringList &id);
+    void findTypeDeclaration(const QStringList &id);
+    void rememberLocation(const QmlJS::AST::SourceLocation &loc);
 
 private:
-    bool _resolveTarget;
     quint32 _pos;
-    QMap<QString, QmlJS::AST::SourceLocation> _idPositions;
+    DuiDocument::Ptr _doc;
+    Snapshot _snapshot;
     int _linkPosition;
     int _linkLength;
+    QString _fileName;
     int _targetLine;
     int _targetColumn;
     QStack<QmlJS::AST::Node*> _scopes;