diff --git a/src/libs/qmljs/qmljs-lib.pri b/src/libs/qmljs/qmljs-lib.pri
index d63d85bc21bff8f39c2ed75b286ee108acb30212..4d450da21b6e88f61970e0485423328b48a7a6fb 100644
--- a/src/libs/qmljs/qmljs-lib.pri
+++ b/src/libs/qmljs/qmljs-lib.pri
@@ -22,7 +22,8 @@ HEADERS += \
     $$PWD/qmljsscanner.h \
     $$PWD/qmljssymbol.h \
     $$PWD/qmljstypesystem.h \
-    $$PWD/qmljsinterpreter.h
+    $$PWD/qmljsinterpreter.h \
+    $$PWD/qmljsmetatypesystem.h
 
 SOURCES += \
     $$PWD/qmljsbind.cpp \
@@ -34,7 +35,8 @@ SOURCES += \
     $$PWD/qmljsscanner.cpp \
     $$PWD/qmljssymbol.cpp \
     $$PWD/qmljstypesystem.cpp \
-    $$PWD/qmljsinterpreter.cpp
+    $$PWD/qmljsinterpreter.cpp \
+    $$PWD/qmljsmetatypesystem.cpp
 
 contains(QT_CONFIG, declarative) {
     QT += declarative
diff --git a/src/libs/qmljs/qmljsbind.cpp b/src/libs/qmljs/qmljsbind.cpp
index 299b13179e14d717cf8e8699dfcc0ace3f3d8225..0354c9992acbf2133deba7f7581748abac8c3a83 100644
--- a/src/libs/qmljs/qmljsbind.cpp
+++ b/src/libs/qmljs/qmljsbind.cpp
@@ -27,10 +27,13 @@
 **
 **************************************************************************/
 
-#include "qmljsbind.h"
 #include "parser/qmljsast_p.h"
+#include "qmljsbind.h"
+#include "qmljsmetatypesystem.h"
 
 using namespace QmlJS;
+using namespace QmlJS::AST;
+using namespace QmlJS::Interpreter;
 
 Bind::Bind()
 {
@@ -40,462 +43,629 @@ Bind::~Bind()
 {
 }
 
-void Bind::operator()(Document::Ptr doc)
+Interpreter::ObjectValue *Bind::operator()(Document::Ptr doc, Snapshot &snapshot, UiObjectMember *member, Interpreter::Engine &interp)
 {
+    UiProgram *program = doc->qmlProgram();
+    if (!program)
+        return 0;
+
     _doc = doc;
+    _snapshot = &snapshot;
+    _interestingMember = member;
+    _interp = &interp;
+
+    _currentObjectValue = 0;
+    _typeEnvironment = _interp->newObject(0);
+    _idEnvironment = _interp->newObject(0);
+    _interestingObjectValue = 0;
+    _rootObjectValue = 0;
+
+    accept(program);
+
+    if (_interestingObjectValue) {
+        _idEnvironment->setScope(_interestingObjectValue);
+
+        if (_interestingObjectValue != _rootObjectValue)
+            _interestingObjectValue->setScope(_rootObjectValue);
+    } else {
+        _idEnvironment->setScope(_rootObjectValue);
+    }
+    _typeEnvironment->setScope(_idEnvironment);
+
+    return _typeEnvironment;
 }
 
-void Bind::accept(AST::Node *node)
+void Bind::accept(Node *node)
 {
-    AST::Node::accept(node, this);
+    Node::accept(node, this);
 }
 
-bool Bind::visit(AST::UiProgram *)
+bool Bind::visit(UiProgram *)
 {
     return true;
 }
 
-bool Bind::visit(AST::UiImportList *)
+bool Bind::visit(UiImportList *)
 {
     return true;
 }
 
-bool Bind::visit(AST::UiImport *)
+static QString serialize(UiQualifiedId *qualifiedId, QChar delimiter)
 {
-    return true;
+    QString result;
+
+    for (UiQualifiedId *iter = qualifiedId; iter; iter = iter->next) {
+        if (iter != qualifiedId)
+            result += delimiter;
+
+        if (iter->name)
+            result += iter->name->asString();
+    }
+
+    return result;
 }
 
-bool Bind::visit(AST::UiPublicMember *)
+/*
+  import Qt 4.6
+  import Qt 4.6 as Xxx
+  (import com.nokia.qt is the same as the ones above)
+
+  import "content"
+  import "content" as Xxx
+  import "content" 4.6
+  import "content" 4.6 as Xxx
+
+  import "http://www.ovi.com/" as Ovi
+ */
+bool Bind::visit(UiImport *ast)
 {
-    return true;
+    ObjectValue *namespaceObject;
+
+    if (ast->asToken.isValid()) { // with namespace we insert an object in the type env. to hold the imported types
+        namespaceObject = _interp->newObject(0);
+        if (!ast->importId)
+            return false; // this should never happen, but better be safe than sorry
+        _typeEnvironment->setProperty(ast->importId->asString(), namespaceObject);
+    } else { // without namespace we insert all types directly into the type env.
+        namespaceObject = _typeEnvironment;
+    }
+
+    // look at files first
+
+    // else try the metaobject system
+    if (!ast->importUri)
+        return false;
+
+    const QString package = serialize(ast->importUri, '/');
+    int majorVersion = -1; // ### TODO: Check these magic version numbers
+    int minorVersion = -1; // ### TODO: Check these magic version numbers
+
+    if (ast->versionToken.isValid()) {
+        const QString versionString = _doc->source().mid(ast->versionToken.offset, ast->versionToken.length);
+        int dotIdx = versionString.indexOf('.');
+        if (dotIdx == -1) {
+            // only major (which is probably invalid, but let's handle it anyway)
+            majorVersion = versionString.toInt();
+            minorVersion = 0; // ### TODO: Check with magic version numbers above
+        } else {
+            majorVersion = versionString.left(dotIdx).toInt();
+            minorVersion = versionString.mid(dotIdx + 1).toInt();
+        }
+    }
+
+#ifndef NO_DECLARATIVE_BACKEND
+    foreach (QmlObjectValue *object, _interp->metaTypeSystem().staticTypesForImport(package, majorVersion, minorVersion)) {
+        namespaceObject->setProperty(object->qmlTypeName(), object);
+    }
+#endif // NO_DECLARATIVE_BACKEND
+
+    return false;
 }
 
-bool Bind::visit(AST::UiSourceElement *)
+bool Bind::visit(UiPublicMember *ast)
 {
-    return true;
+    if (! (ast->name && ast->memberType))
+        return false;
+
+    const QString propName = ast->name->asString();
+    const QString propType = ast->memberType->asString();
+
+    // ### TODO: generalize
+    if (propType == QLatin1String("string"))
+        _currentObjectValue->setProperty(propName, _interp->stringValue());
+    else if (propType == QLatin1String("bool"))
+        _currentObjectValue->setProperty(propName, _interp->booleanValue());
+    else if (propType == QLatin1String("int") || propType == QLatin1String("real"))
+        _currentObjectValue->setProperty(propName, _interp->numberValue());
+
+    return false;
 }
 
-bool Bind::visit(AST::UiObjectDefinition *)
+bool Bind::visit(UiSourceElement *)
 {
     return true;
 }
 
-bool Bind::visit(AST::UiObjectInitializer *)
+const ObjectValue *Bind::lookupType(UiQualifiedId *qualifiedTypeNameId)
 {
-    return true;
+    const ObjectValue *objectValue = _typeEnvironment;
+
+    for (UiQualifiedId *iter = qualifiedTypeNameId; iter; iter = iter->next) {
+        if (! (iter->name))
+            return 0;
+        const Value *value = objectValue->property(iter->name->asString());
+        if (!value)
+            return 0;
+        objectValue = value->asObjectValue();
+        if (!objectValue)
+            return 0;
+    }
+
+    return objectValue;
 }
 
-bool Bind::visit(AST::UiObjectBinding *)
+ObjectValue *Bind::bindObject(UiQualifiedId *qualifiedTypeNameId, UiObjectInitializer *initializer)
 {
-    return true;
+    const ObjectValue *prototype = lookupType(qualifiedTypeNameId);
+    ObjectValue *objectValue = _interp->newObject(prototype);
+    ObjectValue *oldObjectValue = switchObjectValue(objectValue);
+    if (oldObjectValue)
+        objectValue->setProperty("parent", oldObjectValue);
+    else
+        _rootObjectValue = objectValue;
+
+    accept(initializer);
+
+    return switchObjectValue(oldObjectValue);
+}
+
+bool Bind::visit(UiObjectDefinition *ast)
+{
+    ObjectValue *value = bindObject(ast->qualifiedTypeNameId, ast->initializer);
+
+    if (_interestingMember == ast)
+        _interestingObjectValue = value;
+    return false;
 }
 
-bool Bind::visit(AST::UiScriptBinding *)
+bool Bind::visit(UiObjectBinding *ast)
+{
+//    const QString name = serialize(ast->qualifiedId);
+    ObjectValue *value = bindObject(ast->qualifiedTypeNameId, ast->initializer);
+    // ### FIXME: we don't handle dot-properties correctly (i.e. font.size)
+//    _currentObjectValue->setProperty(name, value);
+
+    if (_interestingMember == ast)
+        _interestingObjectValue = value;
+    return false;
+}
+
+bool Bind::visit(UiObjectInitializer *)
 {
     return true;
 }
 
-bool Bind::visit(AST::UiArrayBinding *)
+bool Bind::visit(UiScriptBinding *ast)
+{
+    if (!(ast->qualifiedId->next) && ast->qualifiedId->name->asString() == "id")
+        if (ExpressionStatement *e = cast<ExpressionStatement*>(ast->statement))
+            if (IdentifierExpression *i = cast<IdentifierExpression*>(e->expression))
+                if (i->name)
+                    _idEnvironment->setProperty(i->name->asString(), _currentObjectValue);
+
+    return false;
+}
+
+bool Bind::visit(UiArrayBinding *)
 {
+    // ### FIXME: do we need to store the members into the property? Or, maybe the property type is an JS Array?
+
     return true;
 }
 
-bool Bind::visit(AST::UiObjectMemberList *)
+bool Bind::visit(UiObjectMemberList *)
 {
     return true;
 }
 
-bool Bind::visit(AST::UiArrayMemberList *)
+bool Bind::visit(UiArrayMemberList *)
 {
     return true;
 }
 
-bool Bind::visit(AST::UiQualifiedId *)
+bool Bind::visit(UiQualifiedId *)
 {
     return true;
 }
 
-bool Bind::visit(AST::UiSignature *)
+bool Bind::visit(UiSignature *)
 {
     return true;
 }
 
-bool Bind::visit(AST::UiFormalList *)
+bool Bind::visit(UiFormalList *)
 {
     return true;
 }
 
-bool Bind::visit(AST::UiFormal *)
+bool Bind::visit(UiFormal *)
 {
     return true;
 }
 
-bool Bind::visit(AST::ThisExpression *)
+bool Bind::visit(ThisExpression *)
 {
     return true;
 }
 
-bool Bind::visit(AST::IdentifierExpression *)
+bool Bind::visit(IdentifierExpression *)
 {
     return true;
 }
 
-bool Bind::visit(AST::NullExpression *)
+bool Bind::visit(NullExpression *)
 {
     return true;
 }
 
-bool Bind::visit(AST::TrueLiteral *)
+bool Bind::visit(TrueLiteral *)
 {
     return true;
 }
 
-bool Bind::visit(AST::FalseLiteral *)
+bool Bind::visit(FalseLiteral *)
 {
     return true;
 }
 
-bool Bind::visit(AST::StringLiteral *)
+bool Bind::visit(StringLiteral *)
 {
     return true;
 }
 
-bool Bind::visit(AST::NumericLiteral *)
+bool Bind::visit(NumericLiteral *)
 {
     return true;
 }
 
-bool Bind::visit(AST::RegExpLiteral *)
+bool Bind::visit(RegExpLiteral *)
 {
     return true;
 }
 
-bool Bind::visit(AST::ArrayLiteral *)
+bool Bind::visit(ArrayLiteral *)
 {
     return true;
 }
 
-bool Bind::visit(AST::ObjectLiteral *)
+bool Bind::visit(ObjectLiteral *)
 {
     return true;
 }
 
-bool Bind::visit(AST::ElementList *)
+bool Bind::visit(ElementList *)
 {
     return true;
 }
 
-bool Bind::visit(AST::Elision *)
+bool Bind::visit(Elision *)
 {
     return true;
 }
 
-bool Bind::visit(AST::PropertyNameAndValueList *)
+bool Bind::visit(PropertyNameAndValueList *)
 {
     return true;
 }
 
-bool Bind::visit(AST::NestedExpression *)
+bool Bind::visit(NestedExpression *)
 {
     return true;
 }
 
-bool Bind::visit(AST::IdentifierPropertyName *)
+bool Bind::visit(IdentifierPropertyName *)
 {
     return true;
 }
 
-bool Bind::visit(AST::StringLiteralPropertyName *)
+bool Bind::visit(StringLiteralPropertyName *)
 {
     return true;
 }
 
-bool Bind::visit(AST::NumericLiteralPropertyName *)
+bool Bind::visit(NumericLiteralPropertyName *)
 {
     return true;
 }
 
-bool Bind::visit(AST::ArrayMemberExpression *)
+bool Bind::visit(ArrayMemberExpression *)
 {
     return true;
 }
 
-bool Bind::visit(AST::FieldMemberExpression *)
+bool Bind::visit(FieldMemberExpression *)
 {
     return true;
 }
 
-bool Bind::visit(AST::NewMemberExpression *)
+bool Bind::visit(NewMemberExpression *)
 {
     return true;
 }
 
-bool Bind::visit(AST::NewExpression *)
+bool Bind::visit(NewExpression *)
 {
     return true;
 }
 
-bool Bind::visit(AST::CallExpression *)
+bool Bind::visit(CallExpression *)
 {
     return true;
 }
 
-bool Bind::visit(AST::ArgumentList *)
+bool Bind::visit(ArgumentList *)
 {
     return true;
 }
 
-bool Bind::visit(AST::PostIncrementExpression *)
+bool Bind::visit(PostIncrementExpression *)
 {
     return true;
 }
 
-bool Bind::visit(AST::PostDecrementExpression *)
+bool Bind::visit(PostDecrementExpression *)
 {
     return true;
 }
 
-bool Bind::visit(AST::DeleteExpression *)
+bool Bind::visit(DeleteExpression *)
 {
     return true;
 }
 
-bool Bind::visit(AST::VoidExpression *)
+bool Bind::visit(VoidExpression *)
 {
     return true;
 }
 
-bool Bind::visit(AST::TypeOfExpression *)
+bool Bind::visit(TypeOfExpression *)
 {
     return true;
 }
 
-bool Bind::visit(AST::PreIncrementExpression *)
+bool Bind::visit(PreIncrementExpression *)
 {
     return true;
 }
 
-bool Bind::visit(AST::PreDecrementExpression *)
+bool Bind::visit(PreDecrementExpression *)
 {
     return true;
 }
 
-bool Bind::visit(AST::UnaryPlusExpression *)
+bool Bind::visit(UnaryPlusExpression *)
 {
     return true;
 }
 
-bool Bind::visit(AST::UnaryMinusExpression *)
+bool Bind::visit(UnaryMinusExpression *)
 {
     return true;
 }
 
-bool Bind::visit(AST::TildeExpression *)
+bool Bind::visit(TildeExpression *)
 {
     return true;
 }
 
-bool Bind::visit(AST::NotExpression *)
+bool Bind::visit(NotExpression *)
 {
     return true;
 }
 
-bool Bind::visit(AST::BinaryExpression *)
+bool Bind::visit(BinaryExpression *)
 {
     return true;
 }
 
-bool Bind::visit(AST::ConditionalExpression *)
+bool Bind::visit(ConditionalExpression *)
 {
     return true;
 }
 
-bool Bind::visit(AST::Expression *)
+bool Bind::visit(Expression *)
 {
     return true;
 }
 
-bool Bind::visit(AST::Block *)
+bool Bind::visit(Block *)
 {
     return true;
 }
 
-bool Bind::visit(AST::StatementList *)
+bool Bind::visit(StatementList *)
 {
     return true;
 }
 
-bool Bind::visit(AST::VariableStatement *)
+bool Bind::visit(VariableStatement *)
 {
     return true;
 }
 
-bool Bind::visit(AST::VariableDeclarationList *)
+bool Bind::visit(VariableDeclarationList *)
 {
     return true;
 }
 
-bool Bind::visit(AST::VariableDeclaration *)
+bool Bind::visit(VariableDeclaration *)
 {
     return true;
 }
 
-bool Bind::visit(AST::EmptyStatement *)
+bool Bind::visit(EmptyStatement *)
 {
     return true;
 }
 
-bool Bind::visit(AST::ExpressionStatement *)
+bool Bind::visit(ExpressionStatement *)
 {
     return true;
 }
 
-bool Bind::visit(AST::IfStatement *)
+bool Bind::visit(IfStatement *)
 {
     return true;
 }
 
-bool Bind::visit(AST::DoWhileStatement *)
+bool Bind::visit(DoWhileStatement *)
 {
     return true;
 }
 
-bool Bind::visit(AST::WhileStatement *)
+bool Bind::visit(WhileStatement *)
 {
     return true;
 }
 
-bool Bind::visit(AST::ForStatement *)
+bool Bind::visit(ForStatement *)
 {
     return true;
 }
 
-bool Bind::visit(AST::LocalForStatement *)
+bool Bind::visit(LocalForStatement *)
 {
     return true;
 }
 
-bool Bind::visit(AST::ForEachStatement *)
+bool Bind::visit(ForEachStatement *)
 {
     return true;
 }
 
-bool Bind::visit(AST::LocalForEachStatement *)
+bool Bind::visit(LocalForEachStatement *)
 {
     return true;
 }
 
-bool Bind::visit(AST::ContinueStatement *)
+bool Bind::visit(ContinueStatement *)
 {
     return true;
 }
 
-bool Bind::visit(AST::BreakStatement *)
+bool Bind::visit(BreakStatement *)
 {
     return true;
 }
 
-bool Bind::visit(AST::ReturnStatement *)
+bool Bind::visit(ReturnStatement *)
 {
     return true;
 }
 
-bool Bind::visit(AST::WithStatement *)
+bool Bind::visit(WithStatement *)
 {
     return true;
 }
 
-bool Bind::visit(AST::SwitchStatement *)
+bool Bind::visit(SwitchStatement *)
 {
     return true;
 }
 
-bool Bind::visit(AST::CaseBlock *)
+bool Bind::visit(CaseBlock *)
 {
     return true;
 }
 
-bool Bind::visit(AST::CaseClauses *)
+bool Bind::visit(CaseClauses *)
 {
     return true;
 }
 
-bool Bind::visit(AST::CaseClause *)
+bool Bind::visit(CaseClause *)
 {
     return true;
 }
 
-bool Bind::visit(AST::DefaultClause *)
+bool Bind::visit(DefaultClause *)
 {
     return true;
 }
 
-bool Bind::visit(AST::LabelledStatement *)
+bool Bind::visit(LabelledStatement *)
 {
     return true;
 }
 
-bool Bind::visit(AST::ThrowStatement *)
+bool Bind::visit(ThrowStatement *)
 {
     return true;
 }
 
-bool Bind::visit(AST::TryStatement *)
+bool Bind::visit(TryStatement *)
 {
     return true;
 }
 
-bool Bind::visit(AST::Catch *)
+bool Bind::visit(Catch *)
 {
     return true;
 }
 
-bool Bind::visit(AST::Finally *)
+bool Bind::visit(Finally *)
 {
     return true;
 }
 
-bool Bind::visit(AST::FunctionDeclaration *)
+bool Bind::visit(FunctionDeclaration *)
 {
     return true;
 }
 
-bool Bind::visit(AST::FunctionExpression *)
+bool Bind::visit(FunctionExpression *)
 {
     return true;
 }
 
-bool Bind::visit(AST::FormalParameterList *)
+bool Bind::visit(FormalParameterList *)
 {
     return true;
 }
 
-bool Bind::visit(AST::FunctionBody *)
+bool Bind::visit(FunctionBody *)
 {
     return true;
 }
 
-bool Bind::visit(AST::Program *)
+bool Bind::visit(Program *)
 {
     return true;
 }
 
-bool Bind::visit(AST::SourceElements *)
+bool Bind::visit(SourceElements *)
 {
     return true;
 }
 
-bool Bind::visit(AST::FunctionSourceElement *)
+bool Bind::visit(FunctionSourceElement *)
 {
     return true;
 }
 
-bool Bind::visit(AST::StatementSourceElement *)
+bool Bind::visit(StatementSourceElement *)
 {
     return true;
 }
 
-bool Bind::visit(AST::DebuggerStatement *)
+bool Bind::visit(DebuggerStatement *)
 {
     return true;
 }
+
+ObjectValue *Bind::switchObjectValue(ObjectValue *newObjectValue)
+{
+    ObjectValue *oldObjectValue = _currentObjectValue;
+    _currentObjectValue = newObjectValue;
+    return oldObjectValue;
+}
diff --git a/src/libs/qmljs/qmljsbind.h b/src/libs/qmljs/qmljsbind.h
index 869c61ef780b66dd342ea4e0fd00b27fa836c365..cb89e2634f2b687c8c1d01765574919da19c8bc0 100644
--- a/src/libs/qmljs/qmljsbind.h
+++ b/src/libs/qmljs/qmljsbind.h
@@ -30,8 +30,9 @@
 #ifndef QMLBIND_H
 #define QMLBIND_H
 
-#include "parser/qmljsastvisitor_p.h"
-#include "qmljsdocument.h"
+#include <qmljs/parser/qmljsastvisitor_p.h>
+#include <qmljs/qmljsdocument.h>
+#include <qmljs/qmljsinterpreter.h>
 
 namespace QmlJS {
 
@@ -41,7 +42,7 @@ public:
     Bind();
     virtual ~Bind();
 
-    void operator()(QmlJS::Document::Ptr doc);
+    Interpreter::ObjectValue* operator()(Document::Ptr doc, Snapshot &snapshot, AST::UiObjectMember *member, Interpreter::Engine &interp);
 
 protected:
     void accept(AST::Node *node);
@@ -140,8 +141,23 @@ protected:
     virtual bool visit(AST::StatementSourceElement *ast);
     virtual bool visit(AST::DebuggerStatement *ast);
 
+protected:
+    Interpreter::ObjectValue *switchObjectValue(Interpreter::ObjectValue *newObjectValue);
+    const Interpreter::ObjectValue *lookupType(AST::UiQualifiedId *qualifiedTypeNameId);
+    Interpreter::ObjectValue *bindObject(AST::UiQualifiedId *qualifiedTypeNameId, AST::UiObjectInitializer *initializer);
+
 private:
-    QmlJS::Document::Ptr _doc;
+    Document::Ptr _doc;
+    Snapshot *_snapshot;
+    AST::UiObjectMember *_interestingMember;
+    Interpreter::Engine *_interp;
+
+    Interpreter::ObjectValue *_currentObjectValue;
+
+    Interpreter::ObjectValue *_typeEnvironment;
+    Interpreter::ObjectValue *_idEnvironment;
+    Interpreter::ObjectValue *_interestingObjectValue;
+    Interpreter::ObjectValue *_rootObjectValue;
 };
 
 } // end of namespace Qml
diff --git a/src/libs/qmljs/qmljsdocument.cpp b/src/libs/qmljs/qmljsdocument.cpp
index 539961d32af35033569fe71aaccbafebcd0cceff..ff736fff68f7c1e0d6f0d406e8aa437503e7013b 100644
--- a/src/libs/qmljs/qmljsdocument.cpp
+++ b/src/libs/qmljs/qmljsdocument.cpp
@@ -225,6 +225,8 @@ void Snapshot::insert(const Document::Ptr &document)
 
 Document::PtrList Snapshot::importedDocuments(const Document::Ptr &doc, const QString &importPath) const
 {
+    // ### TODO: maybe we should add all imported documents in the parse Document::parse() method, regardless of whether they're in the path or not.
+
     Document::PtrList result;
 
     const QString docPath = doc->path() + '/' + importPath;
diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp
index 4d664ee8cc9d62d73f6fc911b2a7cf8bfdcd4360..1389d4d01d7cb24b2481e7bb91dd0bee0c867cf2 100644
--- a/src/libs/qmljs/qmljsinterpreter.cpp
+++ b/src/libs/qmljs/qmljsinterpreter.cpp
@@ -43,8 +43,6 @@
 
 using namespace QmlJS::Interpreter;
 
-namespace {
-
 #ifndef NO_DECLARATIVE_BACKEND
 
 class QmlAttachedKeys: public ObjectValue
@@ -166,93 +164,102 @@ public:
     }
 };
 
-class QmlObjectValue: public ObjectValue
-{
-public:
-    QmlObjectValue(const QMetaObject *metaObject, Engine *engine)
-        : ObjectValue(engine), _metaObject(metaObject)
-    {
-    }
+QmlObjectValue::QmlObjectValue(const QMetaObject *metaObject, const QString &qmlTypeName, int majorVersion, int minorVersion, Engine *engine)
+    : ObjectValue(engine), _metaObject(metaObject), _qmlTypeName(qmlTypeName), _majorVersion(majorVersion), _minorVersion(minorVersion)
+{}
 
-    virtual ~QmlObjectValue() {}
+QmlObjectValue::~QmlObjectValue() {}
 
-    virtual const Value *lookupMember(const QString &name) const
-    {
-        for (int index = 0; index < _metaObject->propertyCount(); ++index) {
-            QMetaProperty prop = _metaObject->property(index);
+const Value *QmlObjectValue::lookupMember(const QString &name) const
+{
+    for (int index = 0; index < _metaObject->propertyCount(); ++index) {
+        QMetaProperty prop = _metaObject->property(index);
 
-            if (name == QString::fromUtf8(prop.name()))
-                return propertyValue(prop);
-        }
+        if (name == QString::fromUtf8(prop.name()))
+            return propertyValue(prop);
+    }
 
-        for (int index = 0; index < _metaObject->methodCount(); ++index) {
-            QMetaMethod method = _metaObject->method(index);
+    for (int index = 0; index < _metaObject->methodCount(); ++index) {
+        QMetaMethod method = _metaObject->method(index);
 
-            const QString signature = QString::fromUtf8(method.signature());
+        const QString signature = QString::fromUtf8(method.signature());
 
-            const int indexOfParen = signature.indexOf(QLatin1Char('('));
-            if (indexOfParen == -1)
-                continue; // skip it, invalid signature.
+        const int indexOfParen = signature.indexOf(QLatin1Char('('));
+        if (indexOfParen == -1)
+            continue; // skip it, invalid signature.
 
-            const QString methodName = signature.left(indexOfParen);
+        const QString methodName = signature.left(indexOfParen);
 
-            if (methodName != name) {
-                continue;
+        if (methodName != name) {
+            continue;
 
-            } else if (method.methodType() == QMetaMethod::Slot && method.access() == QMetaMethod::Public) {
-                return new MetaFunction(method, engine());
+        } else if (method.methodType() == QMetaMethod::Slot && method.access() == QMetaMethod::Public) {
+            return new MetaFunction(method, engine());
 
-            } else if (method.methodType() == QMetaMethod::Signal && method.access() != QMetaMethod::Private) {
-                return new MetaFunction(method, engine());
-            }
+        } else if (method.methodType() == QMetaMethod::Signal && method.access() != QMetaMethod::Private) {
+            return new MetaFunction(method, engine());
         }
-
-        return ObjectValue::lookupMember(name);
     }
 
-    virtual void processMembers(MemberProcessor *processor) const
-    {
-        for (int index = 0; index < _metaObject->propertyCount(); ++index) {
-            QMetaProperty prop = _metaObject->property(index);
+    return ObjectValue::lookupMember(name);
+}
 
-            processor->processProperty(prop.name(), propertyValue(prop));
-        }
+void QmlObjectValue::processMembers(MemberProcessor *processor) const
+{
+    for (int index = 0; index < _metaObject->propertyCount(); ++index) {
+        QMetaProperty prop = _metaObject->property(index);
 
-        for (int index = 0; index < _metaObject->methodCount(); ++index) {
-            QMetaMethod method = _metaObject->method(index);
+        processor->processProperty(prop.name(), propertyValue(prop));
+    }
 
-            const QString signature = QString::fromUtf8(method.signature());
+    for (int index = 0; index < _metaObject->methodCount(); ++index) {
+        QMetaMethod method = _metaObject->method(index);
 
-            const int indexOfParen = signature.indexOf(QLatin1Char('('));
-            if (indexOfParen == -1)
-                continue; // skip it, invalid signature.
+        const QString signature = QString::fromUtf8(method.signature());
 
-            const QString methodName = signature.left(indexOfParen);
+        const int indexOfParen = signature.indexOf(QLatin1Char('('));
+        if (indexOfParen == -1)
+            continue; // skip it, invalid signature.
 
-            if (method.methodType() == QMetaMethod::Slot && method.access() == QMetaMethod::Public) {
-                processor->processSlot(methodName, engine()->undefinedValue());
+        const QString methodName = signature.left(indexOfParen);
 
-            } else if (method.methodType() == QMetaMethod::Signal && method.access() != QMetaMethod::Private) {
-                // process the signal
-                processor->processSignal(methodName, engine()->undefinedValue());
+        if (method.methodType() == QMetaMethod::Slot && method.access() == QMetaMethod::Public) {
+            processor->processSlot(methodName, engine()->undefinedValue());
 
-                QString slotName;
-                slotName += QLatin1String("on");
-                slotName += methodName.at(0).toUpper();
-                slotName += methodName.midRef(1);
+        } else if (method.methodType() == QMetaMethod::Signal && method.access() != QMetaMethod::Private) {
+            // process the signal
+            processor->processSignal(methodName, engine()->undefinedValue());
 
-                // process the generated slot
-                processor->processGeneratedSlot(slotName, engine()->undefinedValue());
-            }
-        }
+            QString slotName;
+            slotName += QLatin1String("on");
+            slotName += methodName.at(0).toUpper();
+            slotName += methodName.midRef(1);
 
-        ObjectValue::processMembers(processor);
+            // process the generated slot
+            processor->processGeneratedSlot(slotName, engine()->undefinedValue());
+        }
     }
 
-    const Value *propertyValue(const QMetaProperty &prop) const {
-        const Value *value = engine()->undefinedValue();
+    ObjectValue::processMembers(processor);
+}
+
+const Value *QmlObjectValue::propertyValue(const QMetaProperty &prop) const
+{
+    if (QmlMetaType::isObject(prop.userType())) {
+        QmlType *qmlPropertyType = QmlMetaType::qmlType(QmlMetaType::metaObjectForType(prop.userType()));
 
-        if (QmlMetaType::isObject(prop.userType())) {
+        if (qmlPropertyType && !qmlPropertyType->qmlTypeName().isEmpty()) {
+            QString typeName = qmlPropertyType->qmlTypeName();
+            int slashIdx = typeName.lastIndexOf(QLatin1Char('/'));
+            QString package;
+            if (slashIdx != -1) {
+                package = typeName.left(slashIdx);
+                typeName = typeName.mid(slashIdx + 1);
+            }
+
+            if (const ObjectValue *objectValue = engine()->newQmlObject(typeName, package, qmlPropertyType->majorVersion(), qmlPropertyType->minorVersion()))
+                return objectValue;
+        } else {
             QString typeName = QString::fromUtf8(prop.typeName());
 
             if (typeName.endsWith(QLatin1Char('*')))
@@ -260,78 +267,78 @@ public:
 
             typeName.replace(QLatin1Char('.'), QLatin1Char('/'));
 
-            if (const ObjectValue *objectValue = engine()->newQmlObject(typeName))
+            if (const ObjectValue *objectValue = engine()->newQmlObject(typeName, "", -1, -1))  // ### we should extend this to lookup the property types in the QmlType object, instead of the QMetaProperty.
                 return objectValue;
         }
-
-        switch (prop.type()) {
-        case QMetaType::QByteArray:
-        case QMetaType::QString:
-        case QMetaType::QUrl:
-            value = engine()->stringValue();
-            break;
-
-        case QMetaType::Bool:
-            value = engine()->booleanValue();
-            break;
-
-        case QMetaType::Int:
-        case QMetaType::Float:
-        case QMetaType::Double:
-            value = engine()->numberValue();
-            break;
-
-        case QMetaType::QFont: {
-            // ### cache
-            ObjectValue *object = engine()->newObject(/*prototype =*/ 0);
-            object->setProperty("family", engine()->stringValue());
-            object->setProperty("weight", engine()->undefinedValue()); // ### make me an object
-            object->setProperty("copitalization", engine()->undefinedValue()); // ### make me an object
-            object->setProperty("bold", engine()->booleanValue());
-            object->setProperty("italic", engine()->booleanValue());
-            object->setProperty("underline", engine()->booleanValue());
-            object->setProperty("overline", engine()->booleanValue());
-            object->setProperty("strikeout", engine()->booleanValue());
-            object->setProperty("pointSize", engine()->numberValue());
-            object->setProperty("pixelSize", engine()->numberValue());
-            object->setProperty("letterSpacing", engine()->numberValue());
-            object->setProperty("wordSpacing", engine()->numberValue());
-            value = object;
-        } break;
-
-        case QMetaType::QPoint:
-        case QMetaType::QPointF: {
-            // ### cache
-            ObjectValue *object = engine()->newObject(/*prototype =*/ 0);
-            object->setProperty("x", engine()->numberValue());
-            object->setProperty("y", engine()->numberValue());
-            value = object;
-        } break;
-
-        case QMetaType::QRect:
-        case QMetaType::QRectF: {
-            // ### cache
-            ObjectValue *object = engine()->newObject(/*prototype =*/ 0);
-            object->setProperty("x", engine()->numberValue());
-            object->setProperty("y", engine()->numberValue());
-            object->setProperty("width", engine()->numberValue());
-            object->setProperty("height", engine()->numberValue());
-            value = object;
-        } break;
-
-        default:
-            break;
-        } // end of switch
-
-        return value;
     }
 
-private:
-    const QMetaObject *_metaObject;
-};
-
+    const Value *value = engine()->undefinedValue();
+
+    switch (prop.type()) {
+    case QMetaType::QByteArray:
+    case QMetaType::QString:
+    case QMetaType::QUrl:
+        value = engine()->stringValue();
+        break;
+
+    case QMetaType::Bool:
+        value = engine()->booleanValue();
+        break;
+
+    case QMetaType::Int:
+    case QMetaType::Float:
+    case QMetaType::Double:
+        value = engine()->numberValue();
+        break;
+
+    case QMetaType::QFont: {
+        // ### cache
+        ObjectValue *object = engine()->newObject(/*prototype =*/ 0);
+        object->setProperty("family", engine()->stringValue());
+        object->setProperty("weight", engine()->undefinedValue()); // ### make me an object
+        object->setProperty("copitalization", engine()->undefinedValue()); // ### make me an object
+        object->setProperty("bold", engine()->booleanValue());
+        object->setProperty("italic", engine()->booleanValue());
+        object->setProperty("underline", engine()->booleanValue());
+        object->setProperty("overline", engine()->booleanValue());
+        object->setProperty("strikeout", engine()->booleanValue());
+        object->setProperty("pointSize", engine()->numberValue());
+        object->setProperty("pixelSize", engine()->numberValue());
+        object->setProperty("letterSpacing", engine()->numberValue());
+        object->setProperty("wordSpacing", engine()->numberValue());
+        value = object;
+    } break;
+
+    case QMetaType::QPoint:
+    case QMetaType::QPointF: {
+        // ### cache
+        ObjectValue *object = engine()->newObject(/*prototype =*/ 0);
+        object->setProperty("x", engine()->numberValue());
+        object->setProperty("y", engine()->numberValue());
+        value = object;
+    } break;
+
+    case QMetaType::QRect:
+    case QMetaType::QRectF: {
+        // ### cache
+        ObjectValue *object = engine()->newObject(/*prototype =*/ 0);
+        object->setProperty("x", engine()->numberValue());
+        object->setProperty("y", engine()->numberValue());
+        object->setProperty("width", engine()->numberValue());
+        object->setProperty("height", engine()->numberValue());
+        value = object;
+    } break;
+
+    default:
+        break;
+    } // end of switch
+
+    return value;
+}
 #endif
 
+namespace {
+
 ////////////////////////////////////////////////////////////////////////////////
 // constructors
 ////////////////////////////////////////////////////////////////////////////////
@@ -1300,8 +1307,9 @@ Engine::Engine()
       _convertToString(this),
       _convertToObject(this)
 {
-
     initializePrototypes();
+
+    _metaTypeSystem.reload(this);
 }
 
 Engine::~Engine()
@@ -1780,19 +1788,19 @@ const Value *Engine::defaultValueForBuiltinType(const QString &typeName) const
     return undefinedValue();
 }
 
-ObjectValue *Engine::newQmlObject(const QString &name)
-{
 #ifndef NO_DECLARATIVE_BACKEND
+QmlObjectValue *Engine::newQmlObject(const QString &name, const QString &prefix, int majorVersion, int minorVersion)
+{
     if (name == QLatin1String("QmlGraphicsAnchors")) {
-        QmlObjectValue *object = new QmlObjectValue(&QmlGraphicsAnchors::staticMetaObject, this);
+        QmlObjectValue *object = new QmlObjectValue(&QmlGraphicsAnchors::staticMetaObject, QLatin1String("Anchors"), -1, -1, this);
         _objects.append(object);
         return object;
     } else if (name == QLatin1String("QmlGraphicsPen")) {
-        QmlObjectValue *object = new QmlObjectValue(&QmlGraphicsPen::staticMetaObject, this);
+        QmlObjectValue *object = new QmlObjectValue(&QmlGraphicsPen::staticMetaObject, QLatin1String("Pen"), -1, -1, this);
         _objects.append(object);
         return object;
     } else if (name == QLatin1String("QmlGraphicsScaleGrid")) {
-        ObjectValue *object = newObject(/*prototype =*/ 0);
+        QmlObjectValue *object = new QmlObjectValue(&QObject::staticMetaObject, QLatin1String("ScaleGrid"), -1, -1, this);
         object->setProperty("left", numberValue());
         object->setProperty("top", numberValue());
         object->setProperty("right", numberValue());
@@ -1801,20 +1809,17 @@ ObjectValue *Engine::newQmlObject(const QString &name)
     }
 
     // ### TODO: add support for QML packages
-    QString componentName;
-    componentName += QLatin1String("Qt/");
-    componentName += name;
-    componentName.replace(QLatin1Char('.'), QLatin1Char('/'));
+    const QString componentName = prefix + QLatin1Char('/') + name;
 
-    if (QmlType *qmlType = QmlMetaType::qmlType(componentName.toUtf8(), 4, 6)) {
-        QmlObjectValue *object = new QmlObjectValue(qmlType->metaObject(), this);
+    if (QmlType *qmlType = QmlMetaType::qmlType(componentName.toUtf8(), majorVersion, minorVersion)) {
+        const QString typeName = qmlType->qmlTypeName();
+        const QString strippedTypeName = typeName.mid(typeName.lastIndexOf('/') + 1);
+        QmlObjectValue *object = new QmlObjectValue(qmlType->metaObject(), strippedTypeName, majorVersion, minorVersion, this);
         _objects.append(object);
         return object;
     }
 
     return 0;
-#else
-    return newObject(/*prototype = */ 0);
-#endif
 }
+#endif
 
diff --git a/src/libs/qmljs/qmljsinterpreter.h b/src/libs/qmljs/qmljsinterpreter.h
index 59716961ba6b11bf88a668040d960837c73d932d..ea61857770c91017ef22248f296e85948d7cd4fd 100644
--- a/src/libs/qmljs/qmljsinterpreter.h
+++ b/src/libs/qmljs/qmljsinterpreter.h
@@ -30,7 +30,8 @@
 #ifndef QMLJS_INTERPRETER_H
 #define QMLJS_INTERPRETER_H
 
-#include "qmljs_global.h"
+#include <qmljs/qmljs_global.h>
+#include <qmljs/qmljsmetatypesystem.h>
 
 #include <QtCore/QList>
 #include <QtCore/QString>
@@ -250,6 +251,36 @@ private:
     QString _className;
 };
 
+#ifndef NO_DECLARATIVE_BACKEND
+
+class QmlObjectValue: public ObjectValue
+{
+public:
+    QmlObjectValue(const QMetaObject *metaObject, const QString &qmlTypeName, int majorVersion, int minorVersion, Engine *engine);
+    virtual ~QmlObjectValue();
+
+    virtual const Value *lookupMember(const QString &name) const;
+    virtual void processMembers(MemberProcessor *processor) const;
+    const Value *propertyValue(const QMetaProperty &prop) const;
+
+    QString qmlTypeName() const
+    { return _qmlTypeName; }
+
+    int majorVersion() const
+    { return _majorVersion; }
+
+    int minorVersion() const
+    { return _minorVersion; }
+
+private:
+    const QMetaObject *_metaObject;
+    QString _qmlTypeName;
+    int _majorVersion;
+    int _minorVersion;
+};
+
+#endif // !NO_DECLARATIVE_BACKEND
+
 class QMLJS_EXPORT Activation: public ObjectValue
 {
 public:
@@ -440,9 +471,11 @@ public:
     const Value *newArray(); // ### remove me
 
     // QML objects
-    ObjectValue *newQmlObject(const QString &name);
     const ObjectValue *qmlKeysObject();
     const Value *defaultValueForBuiltinType(const QString &typeName) const;
+#ifndef NO_DECLARATIVE_BACKEND
+    QmlObjectValue *newQmlObject(const QString &name, const QString &prefix, int majorVersion, int minorVersion);
+#endif
 
     // global object
     ObjectValue *globalObject() const;
@@ -477,6 +510,11 @@ public:
     const Value *convertToObject(const Value *value);
     QString typeId(const Value *value);
 
+    // typing:
+    const MetaTypeSystem &metaTypeSystem() const
+    { return _metaTypeSystem; }
+
+
 private:
     void initializePrototypes();
 
@@ -519,6 +557,8 @@ private:
     ConvertToString _convertToString;
     ConvertToObject _convertToObject;
     TypeId _typeId;
+
+    MetaTypeSystem _metaTypeSystem;
 };
 
 } } // end of namespace QmlJS::Interpreter
diff --git a/src/plugins/qmljseditor/qmlcodecompletion.cpp b/src/plugins/qmljseditor/qmlcodecompletion.cpp
index de3faa557a7620ed3fb7cd1bddcc01047987ecdb..a48f63aa4c08939fa21033cfd64ec5bff31a877b 100644
--- a/src/plugins/qmljseditor/qmlcodecompletion.cpp
+++ b/src/plugins/qmljseditor/qmlcodecompletion.cpp
@@ -33,6 +33,7 @@
 #include "qmllookupcontext.h"
 
 #include <qmljs/parser/qmljsast_p.h>
+#include <qmljs/qmljsbind.h>
 #include <qmljs/qmljsinterpreter.h>
 #include <qmljs/qmljssymbol.h>
 #include <qmljs/qmljsscanner.h>
@@ -112,6 +113,7 @@ static QString qualifiedNameId(AST::UiQualifiedId *it)
     return text;
 }
 
+#if 0
 static Interpreter::ObjectValue *newComponent(Interpreter::Engine *engine, const QString &name,
                                               const QHash<QString, Document::Ptr> &userComponents,
                                               QSet<QString> *processed)
@@ -157,6 +159,7 @@ static Interpreter::ObjectValue *newComponent(Interpreter::Engine *engine,
     QSet<QString> processed;
     return newComponent(engine, name, userComponents, &processed);
 }
+#endif
 
 namespace {
 
@@ -688,6 +691,8 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
 
     SemanticInfo semanticInfo = edit->semanticInfo();
     Document::Ptr qmlDocument = semanticInfo.document;
+    if (qmlDocument.isNull())
+        return -1;
 
     const QFileInfo currentFileInfo(fileName);
     const QString currentFilePath = currentFileInfo.absolutePath();
@@ -701,7 +706,7 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
 
     Interpreter::Engine interp;
 
-    QHash<QString, Document::Ptr> userComponents;
+    QHash<QString, Document::Ptr> userComponents; // ####
 
     foreach (Document::Ptr doc, snapshot) {
         const QFileInfo fileInfo(doc->fileName());
@@ -730,6 +735,7 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
         else if (absolutePath != currentFilePath && ! isImported(qmlDocument, absolutePath))
             continue;
 
+#if 0
         QMapIterator<QString, IdSymbol *> it(doc->ids());
         while (it.hasNext()) {
             it.next();
@@ -746,6 +752,7 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
                 }
             }
         }
+#endif
     }
 
     // Set up the current scope chain.
@@ -765,6 +772,7 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
             }
         }
 
+#if 0
         // ### TODO: remove me. This is just a quick and dirty hack to get some completion
         // for the property definitions.
         SearchPropertyDefinitions searchPropertyDefinitions;
@@ -811,6 +819,10 @@ int QmlCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
 
         if (parentItem)
             scope->setProperty(QLatin1String("parent"), parentItem);
+#endif
+
+        Bind bind;
+        scope = bind(qmlDocument, snapshot, declaringMember, interp);
     }
 
     // Search for the operator that triggered the completion.
diff --git a/tests/auto/qml/qmleditor/lookup/lookup.pro b/tests/auto/qml/qmleditor/lookup/lookup.pro
index c4f210ac940d0048976ddacb9ccbf851a7c8ef5a..1c7d8b2adcbc14ba1ee05cda5a15804cc99f039a 100644
--- a/tests/auto/qml/qmleditor/lookup/lookup.pro
+++ b/tests/auto/qml/qmleditor/lookup/lookup.pro
@@ -14,3 +14,9 @@ SOURCES += tst_lookup.cpp \
 
 HEADERS += $$EDITOR_DIR/qmllookupcontext.h
 RESOURCES += testfiles.qrc
+
+OTHER_FILES += \
+    data/localIdLookup.qml \
+    data/localScriptMethodLookup.qml \
+    data/localScopeLookup.qml \
+    data/localRootLookup.qml