From 7ab665fe61b4fe28fdb141fa66509b3addd55623 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Fri, 15 Jul 2011 17:19:17 +1000 Subject: [PATCH] Cache QML import directories and qmldir files. Also a little less toUtf8(). Change-Id: Iefb255fad9e27553f29b184418e66ce317f1cd89 Reviewed-on: http://codereview.qt.nokia.com/3748 Reviewed-by: Roberto Raggi Reviewed-by: Qt Sanity Bot --- src/declarative/qml/qdeclarativecompiler.cpp | 3 +- src/declarative/qml/qdeclarativedirparser.cpp | 35 +++++- src/declarative/qml/qdeclarativedirparser_p.h | 8 +- src/declarative/qml/qdeclarativeimport.cpp | 132 ++++++++------------- src/declarative/qml/qdeclarativeimport_p.h | 3 +- src/declarative/qml/qdeclarativemetatype.cpp | 2 +- src/declarative/qml/qdeclarativemetatype_p.h | 2 +- src/declarative/qml/qdeclarativetypeloader.cpp | 125 +++++++++++++++++++- src/declarative/qml/qdeclarativetypeloader_p.h | 10 ++ src/declarative/qml/v4/qdeclarativev4compiler_p.h | 1 + 10 files changed, 225 insertions(+), 96 deletions(-) diff --git a/src/declarative/qml/qdeclarativecompiler.cpp b/src/declarative/qml/qdeclarativecompiler.cpp index a597d1b..0f78b0c 100644 --- a/src/declarative/qml/qdeclarativecompiler.cpp +++ b/src/declarative/qml/qdeclarativecompiler.cpp @@ -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; diff --git a/src/declarative/qml/qdeclarativedirparser.cpp b/src/declarative/qml/qdeclarativedirparser.cpp index ba7aca0..6798870 100644 --- a/src/declarative/qml/qdeclarativedirparser.cpp +++ b/src/declarative/qml/qdeclarativedirparser.cpp @@ -41,8 +41,10 @@ #include "private/qdeclarativedirparser_p.h" #include "qdeclarativeerror.h" +#include #include +#include #include 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); } diff --git a/src/declarative/qml/qdeclarativedirparser_p.h b/src/declarative/qml/qdeclarativedirparser_p.h index d40833a..a5df5b4 100644 --- a/src/declarative/qml/qdeclarativedirparser_p.h +++ b/src/declarative/qml/qdeclarativedirparser_p.h @@ -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 _errors; QUrl _url; QString _source; + QString _filePathSouce; QList _components; QList _plugins; #ifdef QT_CREATOR diff --git a/src/declarative/qml/qdeclarativeimport.cpp b/src/declarative/qml/qdeclarativeimport.cpp index a28428c..89b6814 100644 --- a/src/declarative/qml/qdeclarativeimport.cpp +++ b/src/declarative/qml/qdeclarativeimport.cpp @@ -71,7 +71,7 @@ Q_GLOBAL_STATIC(StringStringMap, qmlEnginePluginsWithRegisteredTypes); // stores class QDeclarativeImportedNamespace { public: - QStringList uris; + QList uris; QStringList urls; QList majversions; QList minversions; @@ -79,16 +79,16 @@ public: QList 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 *errors = 0); }; class QDeclarativeImportsPrivate { public: - QDeclarativeImportsPrivate(); + QDeclarativeImportsPrivate(QDeclarativeTypeLoader *loader); ~QDeclarativeImportsPrivate(); bool importExtension(const QString &absoluteFilePath, const QString &uri, @@ -111,6 +111,7 @@ public: QSet qmlDirFilesForWhichPluginsHaveBeenLoaded; QDeclarativeImportedNamespace unqualifiedset; QHash set; + QDeclarativeTypeLoader *typeLoader; }; /*! @@ -134,8 +135,8 @@ QDeclarativeImports::operator =(const QDeclarativeImports ©) 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 *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 *errors) { bool typeRecursionDetected = false; for (int i=0; im_elementName; } -QByteArray QDeclarativeType::qmlTypeName() const +const QByteArray &QDeclarativeType::qmlTypeName() const { return d->m_name; } diff --git a/src/declarative/qml/qdeclarativemetatype_p.h b/src/declarative/qml/qdeclarativemetatype_p.h index ca1d869..239b7ca 100644 --- a/src/declarative/qml/qdeclarativemetatype_p.h +++ b/src/declarative/qml/qdeclarativemetatype_p.h @@ -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; diff --git a/src/declarative/qml/qdeclarativetypeloader.cpp b/src/declarative/qml/qdeclarativetypeloader.cpp index 6bda993..6b9dfc1 100644 --- a/src/declarative/qml/qdeclarativetypeloader.cpp +++ b/src/declarative/qml/qdeclarativetypeloader.cpp @@ -51,9 +51,70 @@ #include #include #include +#include + +#if defined (Q_OS_UNIX) +#include +#include +#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 *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 *files = new QStringHash; + 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 *qmlFilesInDirectory(const QString &path) +{ + QDirIterator dir(path, QDir::Files); + if (!dir.hasNext()) + return 0; + QStringHash *files = new QStringHash; + 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) { } diff --git a/src/declarative/qml/qdeclarativetypeloader_p.h b/src/declarative/qml/qdeclarativetypeloader_p.h index 1ca6f8c..a090f25 100644 --- a/src/declarative/qml/qdeclarativetypeloader_p.h +++ b/src/declarative/qml/qdeclarativetypeloader_p.h @@ -62,6 +62,7 @@ #include #include #include +#include "private/qhashedstring_p.h" #include @@ -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 TypeCache; typedef QHash ScriptCache; typedef QHash QmldirCache; + typedef QStringHash StringSet; + typedef QStringHash ImportDirCache; + typedef QStringHash ImportQmlDirCache; TypeCache m_typeCache; ScriptCache m_scriptCache; QmldirCache m_qmldirCache; + ImportDirCache m_importDirCache; + ImportQmlDirCache m_importQmlDirCache; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QDeclarativeTypeLoader::Options) diff --git a/src/declarative/qml/v4/qdeclarativev4compiler_p.h b/src/declarative/qml/v4/qdeclarativev4compiler_p.h index bf53fef..292519b 100644 --- a/src/declarative/qml/v4/qdeclarativev4compiler_p.h +++ b/src/declarative/qml/v4/qdeclarativev4compiler_p.h @@ -74,6 +74,7 @@ public: struct Expression { + Expression(const QDeclarativeImports &imp) : imports(imp) {} QDeclarativeParser::Object *component; QDeclarativeParser::Object *context; QDeclarativeParser::Property *property; -- 1.7.2.5