Remove "All rights reserved" line from license headers.
[profile/ivi/qtdeclarative.git] / src / declarative / qml / qdeclarativeimport.cpp
index bf261ef..8bdcef9 100644 (file)
@@ -1,8 +1,7 @@
 /****************************************************************************
 **
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
 **
 ** This file is part of the QtDeclarative module of the Qt Toolkit.
 **
@@ -35,6 +34,7 @@
 **
 **
 **
+**
 ** $QT_END_LICENSE$
 **
 ****************************************************************************/
 #include <private/qdeclarativetypenamecache_p.h>
 #include <private/qdeclarativeengine_p.h>
 
-#ifdef Q_OS_SYMBIAN
-#include "private/qcore_symbian_p.h"
-#endif
-
 QT_BEGIN_NAMESPACE
 
 DEFINE_BOOL_CONFIG_OPTION(qmlImportTrace, QML_IMPORT_TRACE)
@@ -65,52 +61,79 @@ static bool greaterThan(const QString &s1, const QString &s2)
     return s1 > s2;
 }
 
+QString resolveLocalUrl(const QString &url, const QString &relative)
+{
+    if (relative.contains(QLatin1Char(':'))) {
+        // contains a host name
+        return QUrl(url).resolved(QUrl(relative)).toString();
+    } else if (relative.isEmpty()) {
+        return url;
+    } else if (relative.at(0) == QLatin1Char('/') || !url.contains(QLatin1Char('/'))) {
+        return relative;
+    } else {
+        if (relative == QLatin1String("."))
+            return url.left(url.lastIndexOf(QLatin1Char('/')) + 1);
+        else if (relative.startsWith(QLatin1String("./")))
+            return url.left(url.lastIndexOf(QLatin1Char('/')) + 1) + relative.mid(2);
+        return url.left(url.lastIndexOf(QLatin1Char('/')) + 1) + relative;
+    }
+}
+
+
+
 typedef QMap<QString, QString> StringStringMap;
 Q_GLOBAL_STATIC(StringStringMap, qmlEnginePluginsWithRegisteredTypes); // stores the uri
 
 class QDeclarativeImportedNamespace 
 {
 public:
-    QStringList uris;
-    QStringList urls;
-    QList<int> majversions;
-    QList<int> minversions;
-    QList<bool> isLibrary;
-    QList<QDeclarativeDirComponents> qmlDirComponents;
-
-
-    bool find_helper(int i, const QByteArray& type, int *vmajor, int *vminor,
-                                 QDeclarativeType** type_return, QUrl* url_return,
-                                 QUrl *base = 0, bool *typeRecursionDetected = 0);
-    bool find(const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return,
-              QUrl* url_return, QUrl *base = 0, QString *errorString = 0);
+    struct Data {
+        QString uri;
+        QString url;
+        int majversion;
+        int minversion;
+        bool isLibrary;
+        QDeclarativeDirComponents qmlDirComponents;
+        QDeclarativeDirScripts qmlDirScripts;
+    };
+    QList<Data> imports;
+
+
+    bool find_helper(QDeclarativeTypeLoader *typeLoader, const Data &data, const QString& type, int *vmajor, int *vminor,
+                                 QDeclarativeType** type_return, QString* url_return,
+                                 QString *base = 0, bool *typeRecursionDetected = 0);
+    bool find(QDeclarativeTypeLoader *typeLoader, const QString& type, int *vmajor, int *vminor, QDeclarativeType** type_return,
+              QString* url_return, QString *base = 0, QList<QDeclarativeError> *errors = 0);
 };
 
 class QDeclarativeImportsPrivate {
 public:
-    QDeclarativeImportsPrivate();
+    QDeclarativeImportsPrivate(QDeclarativeTypeLoader *loader);
     ~QDeclarativeImportsPrivate();
 
     bool importExtension(const QString &absoluteFilePath, const QString &uri, 
                          QDeclarativeImportDatabase *database, QDeclarativeDirComponents* components, 
-                         QString *errorString);
+                         QDeclarativeDirScripts *scripts,
+                         QList<QDeclarativeError> *errors);
 
     QString resolvedUri(const QString &dir_arg, QDeclarativeImportDatabase *database);
     bool add(const QDeclarativeDirComponents &qmldircomponentsnetwork, 
              const QString& uri_arg, const QString& prefix, 
-             int vmaj, int vmin, QDeclarativeScriptParser::Import::Type importType, 
-             QDeclarativeImportDatabase *database, QString *errorString);
-    bool find(const QByteArray& type, int *vmajor, int *vminor, 
-              QDeclarativeType** type_return, QUrl* url_return, QString *errorString);
+             int vmaj, int vmin, QDeclarativeScript::Import::Type importType, 
+             QDeclarativeImportDatabase *database, QList<QDeclarativeError> *errors);
+    bool find(const QString& type, int *vmajor, int *vminor,
+              QDeclarativeType** type_return, QString* url_return, QList<QDeclarativeError> *errors);
 
     QDeclarativeImportedNamespace *findNamespace(const QString& type);
 
-    QUrl base;
+    QUrl baseUrl;
+    QString base;
     int ref;
 
     QSet<QString> qmlDirFilesForWhichPluginsHaveBeenLoaded;
     QDeclarativeImportedNamespace unqualifiedset;
     QHash<QString,QDeclarativeImportedNamespace* > set;
+    QDeclarativeTypeLoader *typeLoader;
 };
 
 /*!
@@ -134,8 +157,8 @@ QDeclarativeImports::operator =(const QDeclarativeImports &copy)
     return *this;
 }
 
-QDeclarativeImports::QDeclarativeImports(
-: d(new QDeclarativeImportsPrivate)
+QDeclarativeImports::QDeclarativeImports(QDeclarativeTypeLoader *typeLoader)
+    : d(new QDeclarativeImportsPrivate(typeLoader))
 {
 }
 
@@ -150,7 +173,8 @@ QDeclarativeImports::~QDeclarativeImports()
 */
 void QDeclarativeImports::setBaseUrl(const QUrl& url)
 {
-    d->base = url;
+    d->baseUrl = url;
+    d->base = url.toString();
 }
 
 /*!
@@ -158,57 +182,79 @@ void QDeclarativeImports::setBaseUrl(const QUrl& url)
 */
 QUrl QDeclarativeImports::baseUrl() const
 {
-    return d->base;
+    return d->baseUrl;
 }
 
-static QDeclarativeTypeNameCache *
-cacheForNamespace(QDeclarativeEngine *engine, const QDeclarativeImportedNamespace &set, 
-                  QDeclarativeTypeNameCache *cache)
+void QDeclarativeImports::populateCache(QDeclarativeTypeNameCache *cache, QDeclarativeEngine *engine) const
 {
-    if (!cache)
-        cache = new QDeclarativeTypeNameCache(engine);
-
-    QList<QDeclarativeType *> types = QDeclarativeMetaType::qmlTypes();
+    const QDeclarativeImportedNamespace &set = d->unqualifiedset;
 
-    for (int ii = 0; ii < set.uris.count(); ++ii) {
-        QByteArray base = set.uris.at(ii).toUtf8() + '/';
-        int major = set.majversions.at(ii);
-        int minor = set.minversions.at(ii);
+    for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
+        const QDeclarativeImportedNamespace::Data &data = set.imports.at(ii);
+        QDeclarativeTypeModule *module = QDeclarativeMetaType::typeModule(data.uri, data.majversion);
+        if (module)
+            cache->m_anonymousImports.append(QDeclarativeTypeModuleVersion(module, data.minversion));
+    }
 
-        foreach (QDeclarativeType *type, types) {
-            if (type->qmlTypeName().startsWith(base) &&
-                type->qmlTypeName().lastIndexOf('/') == (base.length() - 1) &&
-                type->availableInVersion(major,minor))
-            {
-                QString name = QString::fromUtf8(type->qmlTypeName().mid(base.length()));
+    for (QHash<QString,QDeclarativeImportedNamespace* >::ConstIterator iter = d->set.begin();
+         iter != d->set.end(); 
+         ++iter) {
+
+        const QDeclarativeImportedNamespace &set = *iter.value();
+        for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
+            const QDeclarativeImportedNamespace::Data &data = set.imports.at(ii);
+            QDeclarativeTypeModule *module = QDeclarativeMetaType::typeModule(data.uri, data.majversion);
+            if (module) {
+                QDeclarativeTypeNameCache::Import &import = cache->m_namedImports[iter.key()];
+                import.modules.append(QDeclarativeTypeModuleVersion(module, data.minversion));
+            }
 
-                cache->add(name, type);
+            QDeclarativeMetaType::ModuleApi moduleApi = QDeclarativeMetaType::moduleApi(data.uri, data.majversion, data.minversion);
+            if (moduleApi.script || moduleApi.qobject) {
+                QDeclarativeTypeNameCache::Import &import = cache->m_namedImports[iter.key()];
+                QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+                import.moduleApi = ep->moduleApiInstance(moduleApi);
             }
         }
     }
-
-    return cache;
 }
 
-void QDeclarativeImports::populateCache(QDeclarativeTypeNameCache *cache, QDeclarativeEngine *engine) const
+QList<QDeclarativeImports::ScriptReference> QDeclarativeImports::resolvedScripts() const
 {
+    QList<QDeclarativeImports::ScriptReference> scripts;
+
     const QDeclarativeImportedNamespace &set = d->unqualifiedset;
 
-    for (QHash<QString,QDeclarativeImportedNamespace* >::ConstIterator iter = d->set.begin();
-         iter != d->set.end(); ++iter) {
+    for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
+        const QDeclarativeImportedNamespace::Data &data = set.imports.at(ii);
 
-        QDeclarativeTypeNameCache::Data *d = cache->data(iter.key());
-        if (d) {
-            if (!d->typeNamespace)
-                cacheForNamespace(engine, *(*iter), d->typeNamespace);
-        } else {
-            QDeclarativeTypeNameCache *nc = cacheForNamespace(engine, *(*iter), 0);
-            cache->add(iter.key(), nc);
-            nc->release();
+        foreach (const QDeclarativeDirParser::Script &script, data.qmlDirScripts) {
+            ScriptReference ref;
+            ref.nameSpace = script.nameSpace;
+            ref.location = QUrl(data.url).resolved(QUrl(script.fileName));
+            scripts.append(ref);
         }
     }
 
-    cacheForNamespace(engine, set, cache);
+    for (QHash<QString,QDeclarativeImportedNamespace* >::ConstIterator iter = d->set.constBegin();
+         iter != d->set.constEnd();
+         ++iter) {
+        const QDeclarativeImportedNamespace &set = *iter.value();
+
+        for (int ii = set.imports.count() - 1; ii >= 0; --ii) {
+            const QDeclarativeImportedNamespace::Data &data = set.imports.at(ii);
+
+            foreach (const QDeclarativeDirParser::Script &script, data.qmlDirScripts) {
+                ScriptReference ref;
+                ref.nameSpace = script.nameSpace;
+                ref.qualifier = iter.key();
+                ref.location = QUrl(data.url).resolved(QUrl(script.fileName));
+                scripts.append(ref);
+            }
+        }
+    }
+
+    return scripts;
 }
 
 /*!
@@ -225,18 +271,18 @@ void QDeclarativeImports::populateCache(QDeclarativeTypeNameCache *cache, QDecla
 
   \sa addImport()
 */
-bool QDeclarativeImports::resolveType(const QByteArray& type, 
-                                      QDeclarativeType** type_return, QUrl* url_return, int *vmaj, int *vmin,
-                                      QDeclarativeImportedNamespace** ns_return, QString *errorString) const
+bool QDeclarativeImports::resolveType(const QString& type,
+                                      QDeclarativeType** type_return, QString* url_return, int *vmaj, int *vmin,
+                                      QDeclarativeImportedNamespace** ns_return, QList<QDeclarativeError> *errors) const
 {
-    QDeclarativeImportedNamespace* ns = d->findNamespace(QString::fromUtf8(type));
+    QDeclarativeImportedNamespace* ns = d->findNamespace(type);
     if (ns) {
         if (ns_return)
             *ns_return = ns;
         return true;
     }
     if (type_return || url_return) {
-        if (d->find(type,vmaj,vmin,type_return,url_return, errorString)) {
+        if (d->find(type,vmaj,vmin,type_return,url_return, errors)) {
             if (qmlImportTrace()) {
                 if (type_return && *type_return && url_return && !url_return->isEmpty())
                     qDebug().nospace() << "QDeclarativeImports(" << qPrintable(baseUrl().toString()) << ")" << "::resolveType: " 
@@ -264,48 +310,44 @@ bool QDeclarativeImports::resolveType(const QByteArray& type,
 
   If either return pointer is 0, the corresponding search is not done.
 */
-bool QDeclarativeImports::resolveType(QDeclarativeImportedNamespace* ns, const QByteArray& type, 
-                                      QDeclarativeType** type_return, QUrl* url_return, 
+bool QDeclarativeImports::resolveType(QDeclarativeImportedNamespace* ns, const QString& type,
+                                      QDeclarativeType** type_return, QString* url_return,
                                       int *vmaj, int *vmin) const
 {
-    return ns->find(type,vmaj,vmin,type_return,url_return);
+    return ns->find(d->typeLoader,type,vmaj,vmin,type_return,url_return);
 }
 
-bool QDeclarativeImportedNamespace::find_helper(int i, const QByteArray& type, int *vmajor, int *vminor,
-                                 QDeclarativeType** type_return, QUrl* url_return,
-                                 QUrl *base, bool *typeRecursionDetected)
+bool QDeclarativeImportedNamespace::find_helper(QDeclarativeTypeLoader *typeLoader, const Data &data, const QString& type, int *vmajor, int *vminor,
+                                 QDeclarativeType** type_return, QString* url_return,
+                                 QString *base, bool *typeRecursionDetected)
 {
-    int vmaj = majversions.at(i);
-    int vmin = minversions.at(i);
-
-    QByteArray qt = uris.at(i).toUtf8();
-    qt += '/';
-    qt += type;
-
-    QDeclarativeType *t = QDeclarativeMetaType::qmlType(qt,vmaj,vmin);
-    if (t) {
-        if (vmajor) *vmajor = vmaj;
-        if (vminor) *vminor = vmin;
-        if (type_return)
-            *type_return = t;
-        return true;
+    int vmaj = data.majversion;
+    int vmin = data.minversion;
+
+    if (vmaj >= 0 && vmin >= 0) {
+        QString qt = data.uri + QLatin1Char('/') + type;
+        QDeclarativeType *t = QDeclarativeMetaType::qmlType(qt,vmaj,vmin);
+        if (t) {
+            if (vmajor) *vmajor = vmaj;
+            if (vminor) *vminor = vmin;
+            if (type_return)
+                *type_return = t;
+            return true;
+        }
     }
 
-    QUrl url = QUrl(urls.at(i) + QLatin1Char('/') + QString::fromUtf8(type) + QLatin1String(".qml"));
-    QDeclarativeDirComponents qmldircomponents = qmlDirComponents.at(i);
-
+    const QDeclarativeDirComponents &qmldircomponents = data.qmlDirComponents;
     bool typeWasDeclaredInQmldir = false;
     if (!qmldircomponents.isEmpty()) {
-        const QString typeName = QString::fromUtf8(type);
         foreach (const QDeclarativeDirParser::Component &c, qmldircomponents) {
-            if (c.typeName == typeName) {
+            if (c.typeName == type) {
                 typeWasDeclaredInQmldir = true;
-
                 // importing version -1 means import ALL versions
-                if ((vmaj == -1) || (c.majorVersion < vmaj || (c.majorVersion == vmaj && vmin >= c.minorVersion))) {
-                    QUrl candidate = url.resolved(QUrl(c.fileName));
+                if ((vmaj == -1) || (c.majorVersion == vmaj && vmin >= c.minorVersion)) {
+                    QString url(data.url + type + QLatin1String(".qml"));
+                    QString candidate = resolveLocalUrl(url, c.fileName);
                     if (c.internal && base) {
-                        if (base->resolved(QUrl(c.fileName)) != candidate)
+                        if (resolveLocalUrl(*base, c.fileName) != candidate)
                             continue; // failed attempt to access an internal type
                     }
                     if (base && *base == candidate) {
@@ -321,10 +363,11 @@ bool QDeclarativeImportedNamespace::find_helper(int i, const QByteArray& type, i
         }
     }
 
-    if (!typeWasDeclaredInQmldir  && !isLibrary.at(i)) {
+    if (!typeWasDeclaredInQmldir && !data.isLibrary) {
         // XXX search non-files too! (eg. zip files, see QT-524)
-        QFileInfo f(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url));
-        if (f.exists()) {
+        QString url(data.url + type + QLatin1String(".qml"));
+        QString file = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url);
+        if (!typeLoader->absoluteFilePath(file).isEmpty()) {
             if (base && *base == url) { // no recursion
                 if (typeRecursionDetected)
                     *typeRecursionDetected = true;
@@ -338,8 +381,8 @@ bool QDeclarativeImportedNamespace::find_helper(int i, const QByteArray& type, i
     return false;
 }
 
-QDeclarativeImportsPrivate::QDeclarativeImportsPrivate(
-: ref(1)
+QDeclarativeImportsPrivate::QDeclarativeImportsPrivate(QDeclarativeTypeLoader *loader)
+    : ref(1), typeLoader(loader)
 {
 }
 
@@ -349,62 +392,66 @@ QDeclarativeImportsPrivate::~QDeclarativeImportsPrivate()
         delete s;
 }
 
-bool QDeclarativeImportsPrivate::importExtension(const QString &absoluteFilePath, const QString &uri, 
-                                                 QDeclarativeImportDatabase *database, 
-                                                 QDeclarativeDirComponents* components, QString *errorString) 
+bool QDeclarativeImportsPrivate::importExtension(const QString &absoluteFilePath, const QString &uri,
+                                                 QDeclarativeImportDatabase *database,
+                                                 QDeclarativeDirComponents* components,
+                                                 QDeclarativeDirScripts* scripts,
+                                                 QList<QDeclarativeError> *errors)
 {
-    QFile file(absoluteFilePath);
-    QString filecontent;
-    if (!QDeclarative_isFileCaseCorrect(absoluteFilePath)) {
-        if (errorString)
-            *errorString = QDeclarativeImportDatabase::tr("cannot load module \"%1\": File name case mismatch for \"%2\"").arg(uri).arg(absoluteFilePath);
-        return false;
-    } else if (file.open(QFile::ReadOnly)) {
-        filecontent = QString::fromUtf8(file.readAll());
-        if (qmlImportTrace())
-            qDebug().nospace() << "QDeclarativeImports(" << qPrintable(base.toString()) << "::importExtension: "
-                               << "loaded " << absoluteFilePath;
-    } else {
-        if (errorString)
-            *errorString = QDeclarativeImportDatabase::tr("module \"%1\" definition \"%2\" not readable").arg(uri).arg(absoluteFilePath);
+    const QDeclarativeDirParser *qmldirParser = typeLoader->qmlDirParser(absoluteFilePath);
+    if (qmldirParser->hasError()) {
+        if (errors) {
+            const QList<QDeclarativeError> qmldirErrors = qmldirParser->errors(uri);
+            for (int i = 0; i < qmldirErrors.size(); ++i)
+                errors->prepend(qmldirErrors.at(i));
+        }
         return false;
     }
-    QDir dir = QFileInfo(file).dir();
 
-    QDeclarativeDirParser qmldirParser;
-    qmldirParser.setSource(filecontent);
-    qmldirParser.parse();
+    if (qmlImportTrace())
+        qDebug().nospace() << "QDeclarativeImports(" << qPrintable(base) << "::importExtension: "
+                           << "loaded " << absoluteFilePath;
 
     if (! qmlDirFilesForWhichPluginsHaveBeenLoaded.contains(absoluteFilePath)) {
         qmlDirFilesForWhichPluginsHaveBeenLoaded.insert(absoluteFilePath);
 
+        QString qmldirPath = absoluteFilePath;
+        int slash = absoluteFilePath.lastIndexOf(QLatin1Char('/'));
+        if (slash > 0)
+            qmldirPath.truncate(slash);
+        foreach (const QDeclarativeDirParser::Plugin &plugin, qmldirParser->plugins()) {
 
-        foreach (const QDeclarativeDirParser::Plugin &plugin, qmldirParser.plugins()) {
-
-            QString resolvedFilePath = database->resolvePlugin(dir, plugin.path, plugin.name);
-#if defined(QT_LIBINFIX) && defined(Q_OS_SYMBIAN)
-            if (resolvedFilePath.isEmpty()) {
-                // In case of libinfixed build, attempt to load libinfixed version, too.
-                QString infixedPluginName = plugin.name + QLatin1String(QT_LIBINFIX);
-                resolvedFilePath = database->resolvePlugin(dir, plugin.path, infixedPluginName);
-            }
-#endif
+            QString resolvedFilePath = database->resolvePlugin(typeLoader, qmldirPath, plugin.path, plugin.name);
             if (!resolvedFilePath.isEmpty()) {
-                if (!database->importPlugin(resolvedFilePath, uri, errorString)) {
-                    if (errorString)
-                        *errorString = QDeclarativeImportDatabase::tr("plugin cannot be loaded for module \"%1\": %2").arg(uri).arg(*errorString);
+                if (!database->importPlugin(resolvedFilePath, uri, errors)) {
+                    if (errors) {
+                        // XXX TODO: should we leave the import plugin error alone?
+                        // Here, we pop it off the top and coalesce it into this error's message.
+                        // The reason is that the lower level may add url and line/column numbering information.
+                        QDeclarativeError poppedError = errors->takeFirst();
+                        QDeclarativeError error;
+                        error.setDescription(QDeclarativeImportDatabase::tr("plugin cannot be loaded for module \"%1\": %2").arg(uri).arg(poppedError.description()));
+                        error.setUrl(QUrl::fromLocalFile(absoluteFilePath));
+                        errors->prepend(error);
+                    }
                     return false;
                 }
             } else {
-                if (errorString)
-                    *errorString = QDeclarativeImportDatabase::tr("module \"%1\" plugin \"%2\" not found").arg(uri).arg(plugin.name);
+                if (errors) {
+                    QDeclarativeError error;
+                    error.setDescription(QDeclarativeImportDatabase::tr("module \"%1\" plugin \"%2\" not found").arg(uri).arg(plugin.name));
+                    error.setUrl(QUrl::fromLocalFile(absoluteFilePath));
+                    errors->prepend(error);
+                }
                 return false;
             }
         }
     }
 
     if (components)
-        *components = qmldirParser.components();
+        *components = qmldirParser->components();
+    if (scripts)
+        *scripts = qmldirParser->scripts();
 
     return true;
 }
@@ -442,10 +489,14 @@ QString QDeclarativeImportsPrivate::resolvedUri(const QString &dir_arg, QDeclara
 
 bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomponentsnetwork, 
                                      const QString& uri_arg, const QString& prefix, int vmaj, int vmin, 
-                                     QDeclarativeScriptParser::Import::Type importType, 
-                                     QDeclarativeImportDatabase *database, QString *errorString)
+                                     QDeclarativeScript::Import::Type importType, 
+                                     QDeclarativeImportDatabase *database, QList<QDeclarativeError> *errors)
 {
+    static QLatin1String Slash_qmldir("/qmldir");
+    static QLatin1Char Slash('/');
+
     QDeclarativeDirComponents qmldircomponents = qmldircomponentsnetwork;
+    QDeclarativeDirScripts qmldirscripts;
     QString uri = uri_arg;
     QDeclarativeImportedNamespace *s;
     if (prefix.isEmpty()) {
@@ -455,118 +506,135 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
         if (!s)
             set.insert(prefix,(s=new QDeclarativeImportedNamespace));
     }
-
     QString url = uri;
     bool versionFound = false;
-    if (importType == QDeclarativeScriptParser::Import::Library) {
-        url.replace(QLatin1Char('.'), QLatin1Char('/'));
+    if (importType == QDeclarativeScript::Import::Library) {
+
+        Q_ASSERT(vmaj >= 0 && vmin >= 0); // Versions are always specified for libraries
+
+        url.replace(QLatin1Char('.'), Slash);
         bool found = false;
         QString dir;
-
+        QString qmldir;
 
         // step 1: search for extension with fully encoded version number
-        if (vmaj >= 0 && vmin >= 0) {
-            foreach (const QString &p, database->fileImportPath) {
-                dir = p+QLatin1Char('/')+url;
+        foreach (const QString &p, database->fileImportPath) {
+            dir = p+Slash+url;
 
-                QFileInfo fi(dir+QString(QLatin1String(".%1.%2")).arg(vmaj).arg(vmin)+QLatin1String("/qmldir"));
-                const QString absoluteFilePath = fi.absoluteFilePath();
+            QFileInfo fi(dir+QString(QLatin1String(".%1.%2")).arg(vmaj).arg(vmin)+QLatin1String("/qmldir"));
+            const QString absoluteFilePath = fi.absoluteFilePath();
 
-                if (fi.isFile()) {
-                    found = true;
+            if (fi.isFile()) {
+                found = true;
 
+                const QString absolutePath = fi.absolutePath();
+                if (absolutePath.at(0) == QLatin1Char(':'))
+                    url = QLatin1String("qrc://") + absolutePath.mid(1);
+                else
                     url = QUrl::fromLocalFile(fi.absolutePath()).toString();
-                    uri = resolvedUri(dir, database);
-                    if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errorString))
-                        return false;
-                    break;
-                }
+                uri = resolvedUri(dir, database);
+                if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, &qmldirscripts, errors))
+                    return false;
+                break;
             }
         }
+
+        // TODO: Should this search be omitted if found == true?
+
         // step 2: search for extension with encoded version major
-        if (vmaj >= 0 && vmin >= 0) {
-            foreach (const QString &p, database->fileImportPath) {
-                dir = p+QLatin1Char('/')+url;
+        foreach (const QString &p, database->fileImportPath) {
+            dir = p+Slash+url;
 
-                QFileInfo fi(dir+QString(QLatin1String(".%1")).arg(vmaj)+QLatin1String("/qmldir"));
-                const QString absoluteFilePath = fi.absoluteFilePath();
+            QFileInfo fi(dir+QString(QLatin1String(".%1")).arg(vmaj)+QLatin1String("/qmldir"));
+            const QString absoluteFilePath = fi.absoluteFilePath();
 
-                if (fi.isFile()) {
-                    found = true;
+            if (fi.isFile()) {
+                found = true;
 
+                const QString absolutePath = fi.absolutePath();
+                if (absolutePath.at(0) == QLatin1Char(':'))
+                    url = QLatin1String("qrc://") + absolutePath.mid(1);
+                else
                     url = QUrl::fromLocalFile(fi.absolutePath()).toString();
-                    uri = resolvedUri(dir, database);
-                    if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errorString))
-                        return false;
-                    break;
-                }
+                uri = resolvedUri(dir, database);
+                if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, &qmldirscripts, errors))
+                    return false;
+                break;
             }
         }
+
         if (!found) {
             // step 3: search for extension without version number
 
             foreach (const QString &p, database->fileImportPath) {
-                dir = p+QLatin1Char('/')+url;
+                dir = p+Slash+url;
+                qmldir = dir+Slash_qmldir;
 
-                QFileInfo fi(dir+QLatin1String("/qmldir"));
-                const QString absoluteFilePath = fi.absoluteFilePath();
-
-                if (fi.isFile()) {
+                QString absoluteFilePath = typeLoader->absoluteFilePath(qmldir);
+                if (!absoluteFilePath.isEmpty()) {
                     found = true;
-
-                    url = QUrl::fromLocalFile(fi.absolutePath()).toString();
+                    QString absolutePath = absoluteFilePath.left(absoluteFilePath.lastIndexOf(Slash)+1);
+                    if (absolutePath.at(0) == QLatin1Char(':'))
+                        url = QLatin1String("qrc://") + absolutePath.mid(1);
+                    else
+                        url = QUrl::fromLocalFile(absolutePath).toString();
                     uri = resolvedUri(dir, database);
-                    if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errorString))
+                    if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, &qmldirscripts, errors))
                         return false;
                     break;
                 }
             }
         }
 
-        if (QDeclarativeMetaType::isModule(uri.toUtf8(), vmaj, vmin))
+        if (QDeclarativeMetaType::isModule(uri, vmaj, vmin))
             versionFound = true;
 
-        if (!versionFound && qmldircomponents.isEmpty()) {
-            if (errorString) {
-                bool anyversion = QDeclarativeMetaType::isModule(uri.toUtf8(), -1, -1);
-                if (anyversion)
-                    *errorString = QDeclarativeImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri_arg).arg(vmaj).arg(vmin);
+        if (!versionFound && qmldircomponents.isEmpty() && qmldirscripts.isEmpty()) {
+            if (errors) {
+                QDeclarativeError error; // we don't set the url or line or column as these will be set by the loader.
+                if (QDeclarativeMetaType::isAnyModule(uri))
+                    error.setDescription(QDeclarativeImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri_arg).arg(vmaj).arg(vmin));
                 else
-                    *errorString = QDeclarativeImportDatabase::tr("module \"%1\" is not installed").arg(uri_arg);
+                    error.setDescription(QDeclarativeImportDatabase::tr("module \"%1\" is not installed").arg(uri_arg));
+                errors->prepend(error);
             }
             return false;
         }
     } else {
-
-        if (importType == QDeclarativeScriptParser::Import::File && qmldircomponents.isEmpty()) {
-            QUrl importUrl = base.resolved(QUrl(uri + QLatin1String("/qmldir")));
+        if (importType == QDeclarativeScript::Import::File && qmldircomponents.isEmpty()) {
+            QString importUrl = resolveLocalUrl(base, uri + Slash_qmldir);
             QString localFileOrQrc = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(importUrl);
             if (!localFileOrQrc.isEmpty()) {
-                QString dir = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(base.resolved(QUrl(uri)));
-                QFileInfo dirinfo(dir);
-                if (dir.isEmpty() || !dirinfo.exists() || !dirinfo.isDir()) {
-                    if (errorString)
-                        *errorString = QDeclarativeImportDatabase::tr("\"%1\": no such directory").arg(uri_arg);
+                QString dir = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(resolveLocalUrl(base, uri));
+                if (!typeLoader->directoryExists(dir)) {
+                    if (errors) {
+                        QDeclarativeError error; // we don't set the line or column as these will be set by the loader.
+                        error.setDescription(QDeclarativeImportDatabase::tr("\"%1\": no such directory").arg(uri_arg));
+                        error.setUrl(QUrl(importUrl));
+                        errors->prepend(error);
+                    }
                     return false; // local import dirs must exist
                 }
-                uri = resolvedUri(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(base.resolved(QUrl(uri))), database);
-                if (uri.endsWith(QLatin1Char('/')))
+                uri = resolvedUri(dir, database);
+                if (uri.endsWith(Slash))
                     uri.chop(1);
-                if (QFile::exists(localFileOrQrc)) {
-                    if (!importExtension(localFileOrQrc,uri,database,&qmldircomponents,errorString))
+                if (!typeLoader->absoluteFilePath(localFileOrQrc).isEmpty()) {
+                    if (!importExtension(localFileOrQrc,uri,database,&qmldircomponents,&qmldirscripts,errors))
                         return false;
                 }
             } else {
                 if (prefix.isEmpty()) {
                     // directory must at least exist for valid import
-                    QString localFileOrQrc = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(base.resolved(QUrl(uri)));
-                    QFileInfo dirinfo(localFileOrQrc);
-                    if (localFileOrQrc.isEmpty() || !dirinfo.exists() || !dirinfo.isDir()) {
-                        if (errorString) {
+                    QString localFileOrQrc = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(resolveLocalUrl(base, uri));
+                    if (!typeLoader->directoryExists(localFileOrQrc)) {
+                        if (errors) {
+                            QDeclarativeError error; // we don't set the line or column as these will be set by the loader.
                             if (localFileOrQrc.isEmpty())
-                                *errorString = QDeclarativeImportDatabase::tr("import \"%1\" has no qmldir and no namespace").arg(uri);
+                                error.setDescription(QDeclarativeImportDatabase::tr("import \"%1\" has no qmldir and no namespace").arg(uri));
                             else
-                                *errorString = QDeclarativeImportDatabase::tr("\"%1\": no such directory").arg(uri);
+                                error.setDescription(QDeclarativeImportDatabase::tr("\"%1\": no such directory").arg(uri));
+                            error.setUrl(QUrl(importUrl));
+                            errors->prepend(error);
                         }
                         return false;
                     }
@@ -574,73 +642,112 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
             }
         }
 
-        url = base.resolved(QUrl(url)).toString();
-        if (url.endsWith(QLatin1Char('/')))
-            url.chop(1);
+        url = resolveLocalUrl(base, url);
     }
 
-    if (!versionFound && vmaj > -1 && vmin > -1 && !qmldircomponents.isEmpty()) {
-        QList<QDeclarativeDirParser::Component>::ConstIterator it = qmldircomponents.begin();
-        int lowest_maj = INT_MAX;
+    if (!versionFound && (vmaj > -1) && (vmin > -1) && !qmldircomponents.isEmpty()) {
         int lowest_min = INT_MAX;
-        int highest_maj = INT_MIN;
         int highest_min = INT_MIN;
-        for (; it != qmldircomponents.end(); ++it) {
-            if (it->majorVersion > highest_maj || (it->majorVersion == highest_maj && it->minorVersion > highest_min)) {
-                highest_maj = it->majorVersion;
-                highest_min = it->minorVersion;
-            }
-            if (it->majorVersion < lowest_maj || (it->majorVersion == lowest_maj && it->minorVersion < lowest_min)) {
-                lowest_maj = it->majorVersion;
-                lowest_min = it->minorVersion;
+
+        QList<QDeclarativeDirParser::Component>::const_iterator cend = qmldircomponents.constEnd();
+        for (QList<QDeclarativeDirParser::Component>::const_iterator cit = qmldircomponents.constBegin(); cit != cend; ++cit) {
+            if (cit->majorVersion == vmaj) {
+                lowest_min = qMin(lowest_min, cit->minorVersion);
+                highest_min = qMax(highest_min, cit->minorVersion);
             }
         }
-        if (lowest_maj > vmaj || (lowest_maj == vmaj && lowest_min > vmin)
-            || highest_maj < vmaj || (highest_maj == vmaj && highest_min < vmin))
-        {
-            *errorString = QDeclarativeImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri_arg).arg(vmaj).arg(vmin);
+
+        if (lowest_min > vmin || highest_min < vmin) {
+            if (errors) {
+                QDeclarativeError error; // we don't set the url or line or column information, as these will be set by the loader.
+                error.setDescription(QDeclarativeImportDatabase::tr("module \"%1\" version %2.%3 is not installed").arg(uri_arg).arg(vmaj).arg(vmin));
+                errors->prepend(error);
+            }
             return false;
         }
     }
 
-    s->uris.prepend(uri);
-    s->urls.prepend(url);
-    s->majversions.prepend(vmaj);
-    s->minversions.prepend(vmin);
-    s->isLibrary.prepend(importType == QDeclarativeScriptParser::Import::Library);
-    s->qmlDirComponents.prepend(qmldircomponents);
+    if (!url.endsWith(Slash))
+        url += Slash;
+
+    QMap<QString, QDeclarativeDirParser::Script> scripts;
+
+    if (!qmldirscripts.isEmpty()) {
+        // Verify that we haven't imported these scripts already
+        QList<QDeclarativeImportedNamespace::Data>::const_iterator end = s->imports.constEnd();
+        for (QList<QDeclarativeImportedNamespace::Data>::const_iterator it = s->imports.constBegin(); it != end; ++it) {
+            if (it->uri == uri) {
+                QDeclarativeError error;
+                error.setDescription(QDeclarativeImportDatabase::tr("\"%1\" is ambiguous. Found in %2 and in %3").arg(uri).arg(url).arg(it->url));
+                errors->prepend(error);
+                return false;
+            }
+        }
+
+        QList<QDeclarativeDirParser::Script>::const_iterator send = qmldirscripts.constEnd();
+        for (QList<QDeclarativeDirParser::Script>::const_iterator sit = qmldirscripts.constBegin(); sit != send; ++sit) {
+            // Only include scripts that match our requested version
+            if (((vmaj == -1) || (sit->majorVersion == vmaj)) &&
+                ((vmin == -1) || (sit->minorVersion <= vmin))) {
+
+                // Load the highest version that matches
+                QMap<QString, QDeclarativeDirParser::Script>::iterator it = scripts.find(sit->nameSpace);
+                if (it == scripts.end() || (it->minorVersion < sit->minorVersion)) {
+                    scripts.insert(sit->nameSpace, *sit);
+                }
+            }
+        }
+    }
+
+    QDeclarativeImportedNamespace::Data data;
+    data.uri = uri;
+    data.url = url;
+    data.majversion = vmaj;
+    data.minversion = vmin;
+    data.isLibrary = importType == QDeclarativeScript::Import::Library;
+    data.qmlDirComponents = qmldircomponents;
+    data.qmlDirScripts = scripts.values();
+
+    s->imports.prepend(data);
+
     return true;
 }
 
-bool QDeclarativeImportsPrivate::find(const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return,
-                                      QUrl* url_return, QString *errorString)
+bool QDeclarativeImportsPrivate::find(const QString& type, int *vmajor, int *vminor, QDeclarativeType** type_return,
+                                      QString* url_return, QList<QDeclarativeError> *errors)
 {
     QDeclarativeImportedNamespace *s = 0;
-    int slash = type.indexOf('/');
+    int slash = type.indexOf(QLatin1Char('/'));
     if (slash >= 0) {
-        QString namespaceName = QString::fromUtf8(type.left(slash));
+        QString namespaceName = type.left(slash);
         s = set.value(namespaceName);
         if (!s) {
-            if (errorString)
-                *errorString = QDeclarativeImportDatabase::tr("- %1 is not a namespace").arg(namespaceName);
+            if (errors) {
+                QDeclarativeError error;
+                error.setDescription(QDeclarativeImportDatabase::tr("- %1 is not a namespace").arg(namespaceName));
+                errors->prepend(error);
+            }
             return false;
         }
-        int nslash = type.indexOf('/',slash+1);
+        int nslash = type.indexOf(QLatin1Char('/'),slash+1);
         if (nslash > 0) {
-            if (errorString)
-                *errorString = QDeclarativeImportDatabase::tr("- nested namespaces not allowed");
+            if (errors) {
+                QDeclarativeError error;
+                error.setDescription(QDeclarativeImportDatabase::tr("- nested namespaces not allowed"));
+                errors->prepend(error);
+            }
             return false;
         }
     } else {
         s = &unqualifiedset;
     }
-    QByteArray unqualifiedtype = slash < 0 ? type : type.mid(slash+1); // common-case opt (QString::mid works fine, but slower)
+    QString unqualifiedtype = slash < 0 ? type : type.mid(slash+1); // common-case opt (QString::mid works fine, but slower)
     if (s) {
-        if (s->find(unqualifiedtype,vmajor,vminor,type_return,url_return, &base, errorString))
+        if (s->find(typeLoader,unqualifiedtype,vmajor,vminor,type_return,url_return, &base, errors))
             return true;
-        if (s->urls.count() == 1 && !s->isLibrary[0] && url_return && s != &unqualifiedset) {
+        if (s->imports.count() == 1 && !s->imports.at(0).isLibrary && url_return && s != &unqualifiedset) {
             // qualified, and only 1 url
-            *url_return = QUrl(s->urls[0]+QLatin1Char('/')).resolved(QUrl(QString::fromUtf8(unqualifiedtype) + QLatin1String(".qml")));
+            *url_return = resolveLocalUrl(s->imports.at(0).url, unqualifiedtype + QLatin1String(".qml"));
             return true;
         }
     }
@@ -653,21 +760,21 @@ QDeclarativeImportedNamespace *QDeclarativeImportsPrivate::findNamespace(const Q
     return set.value(type);
 }
 
-bool QDeclarativeImportedNamespace::find(const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return,
-          QUrl* url_return, QUrl *base, QString *errorString)
+bool QDeclarativeImportedNamespace::find(QDeclarativeTypeLoader *typeLoader, const QString& type, int *vmajor, int *vminor, QDeclarativeType** type_return,
+          QString* url_return, QString *base, QList<QDeclarativeError> *errors)
 {
     bool typeRecursionDetected = false;
-    for (int i=0; i<urls.count(); ++i) {
-        if (find_helper(i, type, vmajor, vminor, type_return, url_return, base, &typeRecursionDetected)) {
+    for (int i=0; i<imports.count(); ++i) {
+        if (find_helper(typeLoader, imports.at(i), type, vmajor, vminor, type_return, url_return, base, &typeRecursionDetected)) {
             if (qmlCheckTypes()) {
                 // check for type clashes
-                for (int j = i+1; j<urls.count(); ++j) {
-                    if (find_helper(j, type, vmajor, vminor, 0, 0, base)) {
-                        if (errorString) {
-                            QString u1 = urls.at(i);
-                            QString u2 = urls.at(j);
+                for (int j = i+1; j<imports.count(); ++j) {
+                    if (find_helper(typeLoader, imports.at(j), type, vmajor, vminor, 0, 0, base)) {
+                        if (errors) {
+                            QString u1 = imports.at(i).url;
+                            QString u2 = imports.at(j).url;
                             if (base) {
-                                QString b = base->toString();
+                                QString b = *base;
                                 int slash = b.lastIndexOf(QLatin1Char('/'));
                                 if (slash >= 0) {
                                     b = b.left(slash+1);
@@ -683,16 +790,16 @@ bool QDeclarativeImportedNamespace::find(const QByteArray& type, int *vmajor, in
                                 }
                             }
 
-                            if (u1 != u2)
-                                *errorString
-                                        = QDeclarativeImportDatabase::tr("is ambiguous. Found in %1 and in %2")
-                                .arg(u1).arg(u2);
-                            else
-                                *errorString
-                                        = QDeclarativeImportDatabase::tr("is ambiguous. Found in %1 in version %2.%3 and %4.%5")
-                                          .arg(u1)
-                                          .arg(majversions.at(i)).arg(minversions.at(i))
-                                          .arg(majversions.at(j)).arg(minversions.at(j));
+                            QDeclarativeError error;
+                            if (u1 != u2) {
+                                error.setDescription(QDeclarativeImportDatabase::tr("is ambiguous. Found in %1 and in %2").arg(u1).arg(u2));
+                            } else {
+                                error.setDescription(QDeclarativeImportDatabase::tr("is ambiguous. Found in %1 in version %2.%3 and %4.%5")
+                                                        .arg(u1)
+                                                        .arg(imports.at(i).majversion).arg(imports.at(i).minversion)
+                                                        .arg(imports.at(j).majversion).arg(imports.at(j).minversion));
+                            }
+                            errors->prepend(error);
                         }
                         return false;
                     }
@@ -701,11 +808,13 @@ bool QDeclarativeImportedNamespace::find(const QByteArray& type, int *vmajor, in
             return true;
         }
     }
-    if (errorString) {
+    if (errors) {
+        QDeclarativeError error;
         if (typeRecursionDetected)
-            *errorString = QDeclarativeImportDatabase::tr("is instantiated recursively");
+            error.setDescription(QDeclarativeImportDatabase::tr("is instantiated recursively"));
         else
-            *errorString = QDeclarativeImportDatabase::tr("is not a type");
+            error.setDescription(QDeclarativeImportDatabase::tr("is not a type"));
+        errors->prepend(error);
     }
     return false;
 }
@@ -724,38 +833,13 @@ QDeclarativeImportDatabase::QDeclarativeImportDatabase(QDeclarativeEngine *e)
 
 #ifndef QT_NO_SETTINGS
     QString installImportsPath =  QLibraryInfo::location(QLibraryInfo::ImportsPath);
-
-#if defined(Q_OS_SYMBIAN)
-    // Append imports path for all available drives in Symbian
-    if (installImportsPath.at(1) != QChar(QLatin1Char(':'))) {
-        QString tempPath = installImportsPath;
-        if (tempPath.at(tempPath.length() - 1) != QDir::separator()) {
-            tempPath += QDir::separator();
-        }
-        RFs& fs = qt_s60GetRFs();
-        TPtrC tempPathPtr(reinterpret_cast<const TText*> (tempPath.constData()));
-        TFindFile finder(fs);
-        TInt err = finder.FindByDir(tempPathPtr, tempPathPtr);
-        while (err == KErrNone) {
-            QString foundDir(reinterpret_cast<const QChar *>(finder.File().Ptr()),
-                             finder.File().Length());
-            foundDir = QDir(foundDir).canonicalPath();
-            addImportPath(foundDir);
-            err = finder.Find();
-        }
-    } else {
-        addImportPath(installImportsPath);
-    }
-#else
     addImportPath(installImportsPath);
-#endif
-
 #endif // QT_NO_SETTINGS
 
     // env import paths
     QByteArray envImportPath = qgetenv("QML_IMPORT_PATH");
     if (!envImportPath.isEmpty()) {
-#if defined(Q_OS_WIN) || defined(Q_OS_SYMBIAN)
+#if defined(Q_OS_WIN)
         QLatin1Char pathSep(';');
 #else
         QLatin1Char pathSep(':');
@@ -788,17 +872,17 @@ QDeclarativeImportDatabase::~QDeclarativeImportDatabase()
 */
 bool QDeclarativeImports::addImport(QDeclarativeImportDatabase *importDb, 
                                     const QString& uri, const QString& prefix, int vmaj, int vmin, 
-                                    QDeclarativeScriptParser::Import::Type importType, 
+                                    QDeclarativeScript::Import::Type importType, 
                                     const QDeclarativeDirComponents &qmldircomponentsnetwork, 
-                                    QString *errorString) 
+                                    QList<QDeclarativeError> *errors)
 {
     if (qmlImportTrace())
         qDebug().nospace() << "QDeclarativeImports(" << qPrintable(baseUrl().toString()) << ")" << "::addImport: " 
                            << uri << " " << vmaj << '.' << vmin << " " 
-                           << (importType==QDeclarativeScriptParser::Import::Library? "Library" : "File") 
+                           << (importType==QDeclarativeScript::Import::Library? "Library" : "File") 
                            << " as " << prefix;
 
-    return d->add(qmldircomponentsnetwork, uri, prefix, vmaj, vmin, importType, importDb, errorString);
+    return d->add(qmldircomponentsnetwork, uri, prefix, vmaj, vmin, importType, importDb, errors);
 }
 
 /*!
@@ -809,7 +893,8 @@ bool QDeclarativeImports::addImport(QDeclarativeImportDatabase *importDb,
 
   \a qmldirPath is the location of the qmldir file.
  */
-QString QDeclarativeImportDatabase::resolvePlugin(const QDir &qmldirPath, const QString &qmldirPluginPath, 
+QString QDeclarativeImportDatabase::resolvePlugin(QDeclarativeTypeLoader *typeLoader,
+                                                  const QString &qmldirPath, const QString &qmldirPluginPath,
                                                   const QString &baseName, const QStringList &suffixes,
                                                   const QString &prefix)
 {
@@ -821,37 +906,40 @@ QString QDeclarativeImportDatabase::resolvePlugin(const QDir &qmldirPath, const
     foreach (const QString &pluginPath, searchPaths) {
 
         QString resolvedPath;
-
         if (pluginPath == QLatin1String(".")) {
-            if (qmldirPluginPathIsRelative)
-                resolvedPath = qmldirPath.absoluteFilePath(qmldirPluginPath);
+            if (qmldirPluginPathIsRelative && !qmldirPluginPath.isEmpty() && qmldirPluginPath != QLatin1String("."))
+                resolvedPath = QDir::cleanPath(qmldirPath + QLatin1Char('/') + qmldirPluginPath);
             else
-                resolvedPath = qmldirPath.absolutePath();
+                resolvedPath = qmldirPath;
         } else {
-            resolvedPath = pluginPath;
+            if (QDir::isRelativePath(pluginPath))
+                resolvedPath = QDir::cleanPath(qmldirPath + QLatin1Char('/') + pluginPath);
+            else
+                resolvedPath = pluginPath;
         }
 
         // hack for resources, should probably go away
         if (resolvedPath.startsWith(QLatin1Char(':')))
             resolvedPath = QCoreApplication::applicationDirPath();
 
-        QDir dir(resolvedPath);
+        if (!resolvedPath.endsWith(QLatin1Char('/')))
+            resolvedPath += QLatin1Char('/');
+
         foreach (const QString &suffix, suffixes) {
             QString pluginFileName = prefix;
 
             pluginFileName += baseName;
             pluginFileName += suffix;
 
-            QFileInfo fileInfo(dir, pluginFileName);
-
-            if (fileInfo.exists())
-                return fileInfo.absoluteFilePath();
+            QString absolutePath = typeLoader->absoluteFilePath(resolvedPath + pluginFileName);
+            if (!absolutePath.isEmpty())
+                return absolutePath;
         }
     }
 
     if (qmlImportTrace())
         qDebug() << "QDeclarativeImportDatabase::resolvePlugin: Could not resolve plugin" << baseName 
-                 << "in" << qmldirPath.absolutePath();
+                 << "in" << qmldirPath;
 
     return QString();
 }
@@ -868,31 +956,26 @@ QString QDeclarativeImportDatabase::resolvePlugin(const QDir &qmldirPath, const
   \row \i AIX  \i \c .a
   \row \i HP-UX       \i \c .sl, \c .so (HP-UXi)
   \row \i Mac OS X    \i \c .dylib, \c .bundle, \c .so
-  \row \i Symbian     \i \c .dll
   \endtable
 
   Version number on unix are ignored.
 */
-QString QDeclarativeImportDatabase::resolvePlugin(const QDir &qmldirPath, const QString &qmldirPluginPath, 
+QString QDeclarativeImportDatabase::resolvePlugin(QDeclarativeTypeLoader *typeLoader,
+                                                  const QString &qmldirPath, const QString &qmldirPluginPath,
                                                   const QString &baseName)
 {
 #if defined(Q_OS_WIN32) || defined(Q_OS_WINCE)
-    return resolvePlugin(qmldirPath, qmldirPluginPath, baseName,
+    return resolvePlugin(typeLoader, qmldirPath, qmldirPluginPath, baseName,
                          QStringList()
 # ifdef QT_DEBUG
                          << QLatin1String("d.dll") // try a qmake-style debug build first
 # endif
                          << QLatin1String(".dll"));
-#elif defined(Q_OS_SYMBIAN)
-    return resolvePlugin(qmldirPath, qmldirPluginPath, baseName,
-                         QStringList()
-                         << QLatin1String(".dll")
-                         << QLatin1String(".qtplugin"));
 #else
 
 # if defined(Q_OS_DARWIN)
 
-    return resolvePlugin(qmldirPath, qmldirPluginPath, baseName,
+    return resolvePlugin(typeLoader, qmldirPath, qmldirPluginPath, baseName,
                          QStringList()
 # ifdef QT_DEBUG
                          << QLatin1String("_debug.dylib") // try a qmake-style debug build first
@@ -926,7 +1009,7 @@ QString QDeclarativeImportDatabase::resolvePlugin(const QDir &qmldirPath, const
     // Examples of valid library names:
     //  libfoo.so
 
-    return resolvePlugin(qmldirPath, qmldirPluginPath, baseName, validSuffixList, QLatin1String("lib"));
+    return resolvePlugin(typeLoader, qmldirPath, qmldirPluginPath, baseName, validSuffixList, QLatin1String("lib"));
 # endif
 
 #endif
@@ -1013,7 +1096,7 @@ void QDeclarativeImportDatabase::setImportPathList(const QStringList &paths)
 /*!
     \internal
 */
-bool QDeclarativeImportDatabase::importPlugin(const QString &filePath, const QString &uri, QString *errorString)
+bool QDeclarativeImportDatabase::importPlugin(const QString &filePath, const QString &uri, QList<QDeclarativeError> *errors)
 {
     if (qmlImportTrace())
         qDebug().nospace() << "QDeclarativeImportDatabase::importPlugin: " << uri << " from " << filePath;
@@ -1033,38 +1116,54 @@ bool QDeclarativeImportDatabase::importPlugin(const QString &filePath, const QSt
 
     if (!engineInitialized || !typesRegistered) {
         if (!QDeclarative_isFileCaseCorrect(absoluteFilePath)) {
-            if (errorString) 
-                *errorString = tr("File name case mismatch for \"%2\"").arg(absoluteFilePath);
+            if (errors) {
+                QDeclarativeError error;
+                error.setDescription(tr("File name case mismatch for \"%1\"").arg(absoluteFilePath));
+                errors->prepend(error);
+            }
             return false;
         }
         QPluginLoader loader(absoluteFilePath);
 
         if (!loader.load()) {
-            if (errorString)
-                *errorString = loader.errorString();
+            if (errors) {
+                QDeclarativeError error;
+                error.setDescription(loader.errorString());
+                errors->prepend(error);
+            }
             return false;
         }
 
-        if (QDeclarativeExtensionInterface *iface = qobject_cast<QDeclarativeExtensionInterface *>(loader.instance())) {
+        QObject *instance = loader.instance();
+        if (QDeclarativeTypesExtensionInterface *iface = qobject_cast<QDeclarativeExtensionInterface *>(instance)) {
 
             const QByteArray bytes = uri.toUtf8();
             const char *moduleId = bytes.constData();
             if (!typesRegistered) {
 
-                // ### this code should probably be protected with a mutex.
+                // XXX thread this code should probably be protected with a mutex.
                 qmlEnginePluginsWithRegisteredTypes()->insert(absoluteFilePath, uri);
                 iface->registerTypes(moduleId);
             }
             if (!engineInitialized) {
-                // things on the engine (eg. adding new global objects) have to be done for every engine.
-
-                // protect against double initialization
+                // things on the engine (eg. adding new global objects) have to be done for every 
+                // engine.  
+                // XXX protect against double initialization
                 initializedPlugins.insert(absoluteFilePath);
-                iface->initializeEngine(engine, moduleId);
+
+                QDeclarativeExtensionInterface *eiface = 
+                    qobject_cast<QDeclarativeExtensionInterface *>(instance);
+                if (eiface) {
+                    QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(engine);
+                    ep->typeLoader.initializeEngine(eiface, moduleId);
+                }
             }
         } else {
-            if (errorString)
-                *errorString = loader.errorString();
+            if (errors) {
+                QDeclarativeError error;
+                error.setDescription(loader.errorString());
+                errors->prepend(error);
+            }
             return false;
         }
     }
@@ -1075,5 +1174,4 @@ bool QDeclarativeImportDatabase::importPlugin(const QString &filePath, const QSt
 #endif
 }
 
-
 QT_END_NAMESPACE