Cache QML import directories and qmldir files.
authorMartin Jones <martin.jones@nokia.com>
Fri, 15 Jul 2011 07:19:17 +0000 (17:19 +1000)
committerQt by Nokia <qt-info@nokia.com>
Tue, 30 Aug 2011 11:18:28 +0000 (13:18 +0200)
Also a little less toUtf8().

Change-Id: Iefb255fad9e27553f29b184418e66ce317f1cd89
Reviewed-on: http://codereview.qt.nokia.com/3748
Reviewed-by: Roberto Raggi <roberto.raggi@nokia.com>
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>

src/declarative/qml/qdeclarativecompiler.cpp
src/declarative/qml/qdeclarativedirparser.cpp
src/declarative/qml/qdeclarativedirparser_p.h
src/declarative/qml/qdeclarativeimport.cpp
src/declarative/qml/qdeclarativeimport_p.h
src/declarative/qml/qdeclarativemetatype.cpp
src/declarative/qml/qdeclarativemetatype_p.h
src/declarative/qml/qdeclarativetypeloader.cpp
src/declarative/qml/qdeclarativetypeloader_p.h
src/declarative/qml/v4/qdeclarativev4compiler_p.h

index a597d1b..0f78b0c 100644 (file)
@@ -2950,11 +2950,10 @@ bool QDeclarativeCompiler::completeComponentBuild()
          aliasObject = compileState->aliasingObjects.next(aliasObject)) 
         COMPILE_CHECK(buildDynamicMeta(aliasObject, ResolveAliases));
 
-    QDeclarativeV4Compiler::Expression expr;
+    QDeclarativeV4Compiler::Expression expr(unit->imports());
     expr.component = compileState->root;
     expr.ids = &compileState->ids;
     expr.importCache = output->importCache;
-    expr.imports = unit->imports();
 
     QDeclarativeV4Compiler bindingCompiler;
 
index ba7aca0..6798870 100644 (file)
 
 #include "private/qdeclarativedirparser_p.h"
 #include "qdeclarativeerror.h"
+#include <private/qdeclarativeglobal_p.h>
 
 #include <QtCore/QTextStream>
+#include <QtCore/QFile>
 #include <QtCore/QtDebug>
 
 QT_BEGIN_NAMESPACE
@@ -66,6 +68,16 @@ void QDeclarativeDirParser::setUrl(const QUrl &url)
     _url = url;
 }
 
+QString QDeclarativeDirParser::fileSource() const
+{
+    return _filePathSouce;
+}
+
+void QDeclarativeDirParser::setFileSource(const QString &filePath)
+{
+    _filePathSouce = filePath;
+}
+
 QString QDeclarativeDirParser::source() const
 {
     return _source;
@@ -92,6 +104,23 @@ bool QDeclarativeDirParser::parse()
     _plugins.clear();
     _components.clear();
 
+    if (_source.isEmpty() && !_filePathSouce.isEmpty()) {
+        QFile file(_filePathSouce);
+        if (!QDeclarative_isFileCaseCorrect(_filePathSouce)) {
+            QDeclarativeError error;
+            error.setDescription(QString::fromUtf8("cannot load module \"%1\": File name case mismatch for \"%2\"").arg(_url.toString()).arg(_filePathSouce));
+            _errors.prepend(error);
+            return false;
+        } else if (file.open(QFile::ReadOnly)) {
+            _source = QString::fromUtf8(file.readAll());
+        } else {
+            QDeclarativeError error;
+            error.setDescription(QString::fromUtf8("module \"%1\" definition \"%2\" not readable").arg(_url.toString()).arg(_filePathSouce));
+            _errors.prepend(error);
+            return false;
+        }
+    }
+
     QTextStream stream(&_source);
     int lineNumber = 0;
 
@@ -157,7 +186,7 @@ bool QDeclarativeDirParser::parse()
                             QString::fromUtf8("internal types require 2 arguments, but %1 were provided").arg(sectionCount - 1));
                 continue;
             }
-            Component entry(sections[1], sections[2], -1, -1);
+            Component entry(sections[1].toUtf8(), sections[2], -1, -1);
             entry.internal = true;
             _components.append(entry);
         } else if (sections[0] == QLatin1String("typeinfo")) {
@@ -173,7 +202,7 @@ bool QDeclarativeDirParser::parse()
 
         } else if (sectionCount == 2) {
             // No version specified (should only be used for relative qmldir files)
-            const Component entry(sections[0], sections[1], -1, -1);
+            const Component entry(sections[0].toUtf8(), sections[1], -1, -1);
             _components.append(entry);
         } else if (sectionCount == 3) {
             const QString &version = sections[1];
@@ -191,7 +220,7 @@ bool QDeclarativeDirParser::parse()
                     const int minorVersion = version.mid(dotIndex + 1).toInt(&validVersionNumber);
 
                     if (validVersionNumber) {
-                        const Component entry(sections[0], sections[2], majorVersion, minorVersion);
+                        const Component entry(sections[0].toUtf8(), sections[2], majorVersion, minorVersion);
 
                         _components.append(entry);
                     }
index d40833a..a5df5b4 100644 (file)
@@ -70,6 +70,9 @@ public:
     QUrl url() const;
     void setUrl(const QUrl &url);
 
+    QString fileSource() const;
+    void setFileSource(const QString &filePath);
+
     QString source() const;
     void setSource(const QString &source);
 
@@ -95,11 +98,11 @@ public:
         Component()
             : majorVersion(0), minorVersion(0), internal(false) {}
 
-        Component(const QString &typeName, const QString &fileName, int majorVersion, int minorVersion)
+        Component(const QByteArray &typeName, const QString &fileName, int majorVersion, int minorVersion)
             : typeName(typeName), fileName(fileName), majorVersion(majorVersion), minorVersion(minorVersion),
             internal(false) {}
 
-        QString typeName;
+        QByteArray typeName;
         QString fileName;
         int majorVersion;
         int minorVersion;
@@ -129,6 +132,7 @@ private:
     QList<QDeclarativeError> _errors;
     QUrl _url;
     QString _source;
+    QString _filePathSouce;
     QList<Component> _components;
     QList<Plugin> _plugins;
 #ifdef QT_CREATOR
index a28428c..89b6814 100644 (file)
@@ -71,7 +71,7 @@ Q_GLOBAL_STATIC(StringStringMap, qmlEnginePluginsWithRegisteredTypes); // stores
 class QDeclarativeImportedNamespace 
 {
 public:
-    QStringList uris;
+    QList<QByteArray> uris;
     QStringList urls;
     QList<int> majversions;
     QList<int> minversions;
@@ -79,16 +79,16 @@ public:
     QList<QDeclarativeDirComponents> qmlDirComponents;
 
 
-    bool find_helper(int i, const QByteArray& type, int *vmajor, int *vminor,
+    bool find_helper(QDeclarativeTypeLoader *typeLoader, 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,
+    bool find(QDeclarativeTypeLoader *typeLoader, const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return,
               QUrl* url_return, QUrl *base = 0, QList<QDeclarativeError> *errors = 0);
 };
 
 class QDeclarativeImportsPrivate {
 public:
-    QDeclarativeImportsPrivate();
+    QDeclarativeImportsPrivate(QDeclarativeTypeLoader *loader);
     ~QDeclarativeImportsPrivate();
 
     bool importExtension(const QString &absoluteFilePath, const QString &uri, 
@@ -111,6 +111,7 @@ public:
     QSet<QString> qmlDirFilesForWhichPluginsHaveBeenLoaded;
     QDeclarativeImportedNamespace unqualifiedset;
     QHash<QString,QDeclarativeImportedNamespace* > set;
+    QDeclarativeTypeLoader *typeLoader;
 };
 
 /*!
@@ -134,8 +135,8 @@ QDeclarativeImports::operator =(const QDeclarativeImports &copy)
     return *this;
 }
 
-QDeclarativeImports::QDeclarativeImports() 
-: d(new QDeclarativeImportsPrivate)
+QDeclarativeImports::QDeclarativeImports(QDeclarativeTypeLoader *typeLoader)
+    : d(new QDeclarativeImportsPrivate(typeLoader))
 {
 }
 
@@ -166,7 +167,7 @@ void QDeclarativeImports::populateCache(QDeclarativeTypeNameCache *cache, QDecla
     const QDeclarativeImportedNamespace &set = d->unqualifiedset;
 
     for (int ii = set.uris.count() - 1; ii >= 0; --ii) {
-        const QByteArray uri = set.uris.at(ii).toUtf8(); // XXX sigh
+        const QByteArray uri = set.uris.at(ii);
         int majversion = set.majversions.at(ii);
         int minversion = set.minversions.at(ii);
         QDeclarativeTypeModule *module = QDeclarativeMetaType::typeModule(uri, majversion);
@@ -180,7 +181,7 @@ void QDeclarativeImports::populateCache(QDeclarativeTypeNameCache *cache, QDecla
         const QDeclarativeImportedNamespace &set = *iter.value();
         QDeclarativeTypeNameCache::Import &import = cache->m_namedImports[iter.key()];
         for (int ii = set.uris.count() - 1; ii >= 0; --ii) {
-            const QByteArray uri = set.uris.at(ii).toUtf8(); // XXX sigh
+            const QByteArray uri = set.uris.at(ii);
             int majversion = set.majversions.at(ii);
             int minversion = set.minversions.at(ii);
             QDeclarativeTypeModule *module = QDeclarativeMetaType::typeModule(uri, majversion);
@@ -261,21 +262,18 @@ bool QDeclarativeImports::resolveType(QDeclarativeImportedNamespace* ns, const Q
                                       QDeclarativeType** type_return, QUrl* 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,
+bool QDeclarativeImportedNamespace::find_helper(QDeclarativeTypeLoader *typeLoader, int i, const QByteArray& type, int *vmajor, int *vminor,
                                  QDeclarativeType** type_return, QUrl* url_return,
                                  QUrl *base, bool *typeRecursionDetected)
 {
-    int vmaj = majversions.at(i);
-    int vmin = minversions.at(i);
+    int vmaj = data.majversion;
+    int vmin = data.minversion;
 
     if (vmaj >= 0 && vmin >= 0) {
-        QByteArray qt = uris.at(i).toUtf8();
-        qt += '/';
-        qt += type;
-
+        QString qt = data.uri + QLatin1Char('/') + type;
         QDeclarativeType *t = QDeclarativeMetaType::qmlType(qt,vmaj,vmin);
         if (t) {
             if (vmajor) *vmajor = vmaj;
@@ -286,18 +284,16 @@ bool QDeclarativeImportedNamespace::find_helper(int i, const QByteArray& type, i
         }
     }
 
-    QUrl url = QUrl(urls.at(i) + QLatin1Char('/') + QString::fromUtf8(type) + QLatin1String(".qml"));
     QDeclarativeDirComponents qmldircomponents = qmlDirComponents.at(i);
-
     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 && vmin >= c.minorVersion)) {
+                    QUrl url = QUrl(urls.at(i) + QLatin1Char('/') + QString::fromUtf8(type) + QLatin1String(".qml"));
                     QUrl candidate = url.resolved(QUrl(c.fileName));
                     if (c.internal && base) {
                         if (base->resolved(QUrl(c.fileName)) != candidate)
@@ -318,8 +314,9 @@ bool QDeclarativeImportedNamespace::find_helper(int i, const QByteArray& type, i
 
     if (!typeWasDeclaredInQmldir  && !isLibrary.at(i)) {
         // XXX search non-files too! (eg. zip files, see QT-524)
-        QFileInfo f(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url));
-        if (f.exists()) {
+        QUrl url = QUrl(urls.at(i) + QLatin1Char('/') + QString::fromUtf8(type) + QLatin1String(".qml"));
+        QString file = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(url);
+        if (!typeLoader->absoluteFilePath(file).isEmpty()) {
             if (base && *base == url) { // no recursion
                 if (typeRecursionDetected)
                     *typeRecursionDetected = true;
@@ -333,8 +330,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)
 {
 }
 
@@ -348,50 +345,24 @@ bool QDeclarativeImportsPrivate::importExtension(const QString &absoluteFilePath
                                                  QDeclarativeImportDatabase *database, 
                                                  QDeclarativeDirComponents* components, QList<QDeclarativeError> *errors)
 {
-    QFile file(absoluteFilePath);
-    QString filecontent;
-    if (!QDeclarative_isFileCaseCorrect(absoluteFilePath)) {
+    const QDeclarativeDirParser *qmldirParser = typeLoader->qmlDirParser(absoluteFilePath);
+    if (qmldirParser->hasError()) {
         if (errors) {
-            QDeclarativeError error;
-            error.setDescription(QDeclarativeImportDatabase::tr("cannot load module \"%1\": File name case mismatch for \"%2\"").arg(uri).arg(absoluteFilePath));
-            errors->prepend(error);
-        }
-        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 (errors) {
-            QDeclarativeError error;
-            error.setDescription(QDeclarativeImportDatabase::tr("module \"%1\" definition \"%2\" not readable").arg(uri).arg(absoluteFilePath));
-            errors->prepend(error);
+            for (int i = 0; i < qmldirParser->errors().size(); ++i)
+                errors->prepend(qmldirParser->errors().at(i));
         }
         return false;
     }
-    QDir dir = QFileInfo(file).dir();
-    QUrl url = QUrl::fromLocalFile(absoluteFilePath);
-
-    QDeclarativeDirParser qmldirParser;
-    qmldirParser.setSource(filecontent);
-    qmldirParser.setUrl(url);
 
-    // propagate any errors reported by the parser back up to the typeloader.
-    if (qmldirParser.parse()) {
-        if (errors) {
-            for (int i = 0; i < qmldirParser.errors().size(); ++i) {
-                errors->prepend(qmldirParser.errors().at(i));
-            }
-        }
-        return false;
-    }
+    if (qmlImportTrace())
+        qDebug().nospace() << "QDeclarativeImports(" << qPrintable(base.toString()) << "::importExtension: "
+                           << "loaded " << absoluteFilePath;
 
     if (! qmlDirFilesForWhichPluginsHaveBeenLoaded.contains(absoluteFilePath)) {
         qmlDirFilesForWhichPluginsHaveBeenLoaded.insert(absoluteFilePath);
 
-
-        foreach (const QDeclarativeDirParser::Plugin &plugin, qmldirParser.plugins()) {
+        QDir dir = QFileInfo(absoluteFilePath).dir();
+        foreach (const QDeclarativeDirParser::Plugin &plugin, qmldirParser->plugins()) {
 
             QString resolvedFilePath = database->resolvePlugin(dir, plugin.path, plugin.name);
 #if defined(QT_LIBINFIX) && defined(Q_OS_SYMBIAN)
@@ -410,7 +381,7 @@ bool QDeclarativeImportsPrivate::importExtension(const QString &absoluteFilePath
                         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(url);
+                        error.setUrl(QUrl::fromLocalFile(absoluteFilePath));
                         errors->prepend(error);
                     }
                     return false;
@@ -419,7 +390,7 @@ bool QDeclarativeImportsPrivate::importExtension(const QString &absoluteFilePath
                 if (errors) {
                     QDeclarativeError error;
                     error.setDescription(QDeclarativeImportDatabase::tr("module \"%1\" plugin \"%2\" not found").arg(uri).arg(plugin.name));
-                    error.setUrl(url);
+                    error.setUrl(QUrl::fromLocalFile(absoluteFilePath));
                     errors->prepend(error);
                 }
                 return false;
@@ -428,7 +399,7 @@ bool QDeclarativeImportsPrivate::importExtension(const QString &absoluteFilePath
     }
 
     if (components)
-        *components = qmldirParser.components();
+        *components = qmldirParser->components();
 
     return true;
 }
@@ -488,11 +459,11 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
         url.replace(QLatin1Char('.'), QLatin1Char('/'));
         bool found = false;
         QString dir;
+        QString qmldir;
 
         // step 1: search for extension with fully encoded version number
-        if (!found) {
-            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();
@@ -509,9 +480,8 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
         }
 
         // step 2: search for extension with encoded version major
-        if (!found) {
-            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();
@@ -532,14 +502,13 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
 
             foreach (const QString &p, database->fileImportPath) {
                 dir = p+QLatin1Char('/')+url;
+                qmldir = dir+QLatin1String("/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(QLatin1Char('/')));
+                    url = QUrl::fromLocalFile(absolutePath).toString();
                     uri = resolvedUri(dir, database);
                     if (!importExtension(absoluteFilePath, uri, database, &qmldircomponents, errors))
                         return false;
@@ -564,7 +533,6 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
             return false;
         }
     } else {
-
         if (importType == QDeclarativeScriptParser::Import::File && qmldircomponents.isEmpty()) {
             QUrl importUrl = base.resolved(QUrl(uri + QLatin1String("/qmldir")));
             QString localFileOrQrc = QDeclarativeEnginePrivate::urlToLocalFileOrQrc(importUrl);
@@ -583,7 +551,7 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
                 uri = resolvedUri(QDeclarativeEnginePrivate::urlToLocalFileOrQrc(base.resolved(QUrl(uri))), database);
                 if (uri.endsWith(QLatin1Char('/')))
                     uri.chop(1);
-                if (QFile::exists(localFileOrQrc)) {
+                if (!typeLoader->absoluteFilePath(localFileOrQrc).isEmpty()) {
                     if (!importExtension(localFileOrQrc,uri,database,&qmldircomponents,errors))
                         return false;
                 }
@@ -633,7 +601,7 @@ bool QDeclarativeImportsPrivate::add(const QDeclarativeDirComponents &qmldircomp
         }
     }
 
-    s->uris.prepend(uri);
+    s->uris.prepend(uri.toUtf8());
     s->urls.prepend(url);
     s->majversions.prepend(vmaj);
     s->minversions.prepend(vmin);
@@ -672,7 +640,7 @@ bool QDeclarativeImportsPrivate::find(const QByteArray& type, int *vmajor, int *
     }
     QByteArray 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, errors))
+        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) {
             // qualified, and only 1 url
@@ -689,16 +657,16 @@ QDeclarativeImportedNamespace *QDeclarativeImportsPrivate::findNamespace(const Q
     return set.value(type);
 }
 
-bool QDeclarativeImportedNamespace::find(const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return,
+bool QDeclarativeImportedNamespace::find(QDeclarativeTypeLoader *typeLoader, const QByteArray& type, int *vmajor, int *vminor, QDeclarativeType** type_return,
           QUrl* url_return, QUrl *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)) {
+        if (find_helper(typeLoader, 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 (find_helper(typeLoader, j, type, vmajor, vminor, 0, 0, base)) {
                         if (errors) {
                             QString u1 = urls.at(i);
                             QString u2 = urls.at(j);
@@ -872,7 +840,6 @@ QString QDeclarativeImportDatabase::resolvePlugin(const QDir &qmldirPath, const
         // hack for resources, should probably go away
         if (resolvedPath.startsWith(QLatin1Char(':')))
             resolvedPath = QCoreApplication::applicationDirPath();
-
         QDir dir(resolvedPath);
         foreach (const QString &suffix, suffixes) {
             QString pluginFileName = prefix;
@@ -1122,5 +1089,4 @@ bool QDeclarativeImportDatabase::importPlugin(const QString &filePath, const QSt
 #endif
 }
 
-
 QT_END_NAMESPACE
index fe9404d..d3e4933 100644 (file)
@@ -68,11 +68,12 @@ class QDir;
 class QDeclarativeImportedNamespace;
 class QDeclarativeImportsPrivate;
 class QDeclarativeImportDatabase;
+class QDeclarativeTypeLoader;
 
 class QDeclarativeImports
 {
 public:
-    QDeclarativeImports();
+    QDeclarativeImports(QDeclarativeTypeLoader *);
     QDeclarativeImports(const QDeclarativeImports &);
     ~QDeclarativeImports();
     QDeclarativeImports &operator=(const QDeclarativeImports &);
index da7be11..bd4b935 100644 (file)
@@ -504,7 +504,7 @@ const QString &QDeclarativeType::elementName() const
     return d->m_elementName;
 }
 
-QByteArray QDeclarativeType::qmlTypeName() const
+const QByteArray &QDeclarativeType::qmlTypeName() const
 {
     return d->m_name;
 }
index ca1d869..239b7ca 100644 (file)
@@ -137,7 +137,7 @@ class Q_DECLARATIVE_PRIVATE_EXPORT QDeclarativeType
 {
 public:
     QByteArray typeName() const;
-    QByteArray qmlTypeName() const;
+    const QByteArray &qmlTypeName() const;
     const QString &elementName() const;
 
     QByteArray module() const;
index 6bda993..6b9dfc1 100644 (file)
 #include <QtCore/qdebug.h>
 #include <QtCore/qdir.h>
 #include <QtCore/qfile.h>
+#include <QtCore/qdiriterator.h>
+
+#if defined (Q_OS_UNIX)
+#include <sys/types.h>
+#include <dirent.h>
+#endif
 
 QT_BEGIN_NAMESPACE
 
+
+/*
+Returns the set of QML files in path (qmldir, *.qml, *.js).  The caller
+is responsible for deleting the returned data.
+*/
+#if defined (Q_OS_UNIX)
+static QStringHash<bool> *qmlFilesInDirectory(const QString &path)
+{
+    QByteArray name(QFile::encodeName(path));
+    DIR *dd = opendir(name);
+    if (!dd)
+        return 0;
+
+    struct dirent *result;
+    union {
+        struct dirent d;
+        char b[offsetof (struct dirent, d_name) + NAME_MAX + 1];
+    } u;
+
+    QStringHash<bool> *files = new QStringHash<bool>;
+    while (readdir_r(dd, &u.d, &result) == 0 && result != 0) {
+        if (!strcmp(u.d.d_name, "qmldir")) {
+            files->insert(QLatin1String("qmldir"), true);
+            continue;
+        }
+        int len = strlen(u.d.d_name);
+        if (len < 4)
+            continue;
+        if (!strcmp(u.d.d_name+len-4, ".qml") || !strcmp(u.d.d_name+len-3, ".js"))
+            files->insert(QFile::decodeName(u.d.d_name), true);
+    }
+
+    closedir(dd);
+    return files;
+}
+#else
+static QStringHash<bool> *qmlFilesInDirectory(const QString &path)
+{
+    QDirIterator dir(path, QDir::Files);
+    if (!dir.hasNext())
+        return 0;
+    QStringHash<bool> *files = new QStringHash<bool>;
+    while (dir.hasNext()) {
+        dir.next();
+        QString fileName = dir.fileName();
+        if (fileName == QLatin1String("qmldir")
+                || fileName.endsWith(QLatin1String(".qml"))
+                || fileName.endsWith(QLatin1String(".js")))
+            files->insert(fileName, true);
+    }
+    return files;
+}
+#endif
+
+
 /*!
 \class QDeclarativeDataBlob
 \brief The QDeclarativeDataBlob encapsulates a data request that can be issued to a QDeclarativeDataLoader.
@@ -723,6 +784,60 @@ QDeclarativeQmldirData *QDeclarativeTypeLoader::getQmldir(const QUrl &url)
 }
 
 /*!
+Returns the absolute filename of path via a directory cache for files named
+"qmldir", "*.qml", "*.js"
+Returns a empty string if the path does not exist.
+*/
+QString QDeclarativeTypeLoader::absoluteFilePath(const QString &path)
+{
+    if (path.isEmpty())
+        return QString();
+    if (path.at(0) == QLatin1Char(':')) {
+        // qrc resource
+        QFileInfo fileInfo(path);
+        return fileInfo.isFile() ? fileInfo.absoluteFilePath() : QString();
+    }
+    int lastSlash = path.lastIndexOf(QLatin1Char('/'));
+    QStringRef dirPath(&path, 0, lastSlash);
+
+    StringSet **fileSet = m_importDirCache.value(QHashedStringRef(dirPath.constData(), dirPath.length()));
+    if (!fileSet) {
+        QHashedString dirPathString(dirPath.toString());
+        StringSet *files = qmlFilesInDirectory(dirPathString);
+        m_importDirCache.insert(dirPathString, files);
+        fileSet = m_importDirCache.value(dirPathString);
+    }
+    if (!(*fileSet))
+        return QString();
+
+    QString absoluteFilePath = (*fileSet)->contains(QHashedStringRef(path.constData()+lastSlash+1, path.length()-lastSlash-1)) ? path : QString();
+    if (absoluteFilePath.length() > 2 && absoluteFilePath.at(0) != QLatin1Char('/') && absoluteFilePath.at(1) != QLatin1Char(':'))
+        absoluteFilePath = QFileInfo(absoluteFilePath).absoluteFilePath();
+
+    return absoluteFilePath;
+}
+
+/*!
+Return a QDeclarativeDirParser for absoluteFilePath.  The QDeclarativeDirParser may be cached.
+*/
+const QDeclarativeDirParser *QDeclarativeTypeLoader::qmlDirParser(const QString &absoluteFilePath)
+{
+    QDeclarativeDirParser *qmldirParser;
+    QDeclarativeDirParser **val = m_importQmlDirCache.value(absoluteFilePath);
+    if (!val) {
+        qmldirParser = new QDeclarativeDirParser;
+        qmldirParser->setFileSource(absoluteFilePath);
+        qmldirParser->setUrl(QUrl::fromLocalFile(absoluteFilePath));
+        qmldirParser->parse();
+        m_importQmlDirCache.insert(absoluteFilePath, qmldirParser);
+    } else {
+        qmldirParser = *val;
+    }
+
+    return qmldirParser;
+}
+
+/*!
 Clears cached information about loaded files, including any type data, scripts
 and qmldir information.
 */
@@ -734,17 +849,21 @@ void QDeclarativeTypeLoader::clearCache()
         (*iter)->release();
     for (QmldirCache::Iterator iter = m_qmldirCache.begin(); iter != m_qmldirCache.end(); ++iter) 
         (*iter)->release();
+    qDeleteAll(m_importDirCache);
+    qDeleteAll(m_importQmlDirCache);
 
     m_typeCache.clear();
     m_scriptCache.clear();
     m_qmldirCache.clear();
+    m_importDirCache.clear();
+    m_importQmlDirCache.clear();
 }
 
 
 QDeclarativeTypeData::QDeclarativeTypeData(const QUrl &url, QDeclarativeTypeLoader::Options options, 
                                            QDeclarativeTypeLoader *manager)
-: QDeclarativeDataBlob(url, QmlFile), m_options(options), m_typesResolved(false), 
-  m_compiledData(0), m_typeLoader(manager)
+: QDeclarativeDataBlob(url, QmlFile), m_options(options), m_imports(manager), m_typesResolved(false),
+   m_compiledData(0), m_typeLoader(manager)
 {
 }
 
@@ -1104,7 +1223,7 @@ void QDeclarativeScriptData::clear()
 
 QDeclarativeScriptBlob::QDeclarativeScriptBlob(const QUrl &url, QDeclarativeTypeLoader *loader)
 : QDeclarativeDataBlob(url, JavaScriptFile), m_pragmas(QDeclarativeParser::Object::ScriptBlock::None),
-  m_scriptData(0), m_typeLoader(loader)
+  m_imports(loader), m_scriptData(0), m_typeLoader(loader)
 {
 }
 
index 1ca6f8c..a090f25 100644 (file)
@@ -62,6 +62,7 @@
 #include <private/qdeclarativescriptparser_p.h>
 #include <private/qdeclarativedirparser_p.h>
 #include <private/qdeclarativeimport_p.h>
+#include "private/qhashedstring_p.h"
 
 #include <private/qv8_p.h>
 
@@ -202,14 +203,23 @@ public:
 
     QDeclarativeScriptBlob *getScript(const QUrl &);
     QDeclarativeQmldirData *getQmldir(const QUrl &);
+
+    QString absoluteFilePath(const QString &path);
+    const QDeclarativeDirParser *qmlDirParser(const QString &absoluteFilePath);
+
 private:
     typedef QHash<QUrl, QDeclarativeTypeData *> TypeCache;
     typedef QHash<QUrl, QDeclarativeScriptBlob *> ScriptCache;
     typedef QHash<QUrl, QDeclarativeQmldirData *> QmldirCache;
+    typedef QStringHash<bool> StringSet;
+    typedef QStringHash<StringSet*> ImportDirCache;
+    typedef QStringHash<QDeclarativeDirParser*> ImportQmlDirCache;
 
     TypeCache m_typeCache;
     ScriptCache m_scriptCache;
     QmldirCache m_qmldirCache;
+    ImportDirCache m_importDirCache;
+    ImportQmlDirCache m_importQmlDirCache;
 };
 
 Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativeTypeLoader::Options)
index bf53fef..292519b 100644 (file)
@@ -74,6 +74,7 @@ public:
 
     struct Expression
     {
+        Expression(const QDeclarativeImports &imp) : imports(imp) {}
         QDeclarativeParser::Object *component;
         QDeclarativeParser::Object *context;
         QDeclarativeParser::Property *property;