diff options
-rw-r--r-- | src/declarative/qml/qmlcompositetypedata_p.h | 3 | ||||
-rw-r--r-- | src/declarative/qml/qmlcompositetypemanager.cpp | 131 | ||||
-rw-r--r-- | src/declarative/qml/qmlcompositetypemanager_p.h | 1 | ||||
-rw-r--r-- | src/declarative/qml/qmlengine.cpp | 65 | ||||
-rw-r--r-- | src/declarative/qml/qmlengine_p.h | 2 | ||||
-rw-r--r-- | src/declarative/qml/qmlscriptparser.cpp | 3 |
6 files changed, 131 insertions, 74 deletions
diff --git a/src/declarative/qml/qmlcompositetypedata_p.h b/src/declarative/qml/qmlcompositetypedata_p.h index fa11137..ffcef4c 100644 --- a/src/declarative/qml/qmlcompositetypedata_p.h +++ b/src/declarative/qml/qmlcompositetypedata_p.h @@ -69,7 +69,8 @@ public: Invalid, Complete, Error, - Waiting + Waiting, + WaitingResources }; Status status; enum ErrorType { diff --git a/src/declarative/qml/qmlcompositetypemanager.cpp b/src/declarative/qml/qmlcompositetypemanager.cpp index 3c76344..9444a22 100644 --- a/src/declarative/qml/qmlcompositetypemanager.cpp +++ b/src/declarative/qml/qmlcompositetypemanager.cpp @@ -352,18 +352,6 @@ void QmlCompositeTypeManager::setData(QmlCompositeTypeData *unit, if (!unit->data.parse(data, url)) { ok = false; unit->errors << unit->data.errors(); - } else { - foreach (QmlScriptParser::Import imp, unit->data.imports()) { - int dot = imp.version.indexOf(QLatin1Char('.')); - if (dot < 0) dot = imp.version.length(); - if (!QmlEnginePrivate::get(engine)->addToImport(&unit->imports, imp.uri, imp.qualifier, imp.version.left(dot).toInt(), imp.version.mid(dot+1).toInt(), imp.type)) { - QmlError error; - error.setUrl(url); - error.setDescription(tr("Import %1 unavailable").arg(imp.uri)); - unit->errors << error; - ok = false; - } - } } if (ok) { @@ -400,25 +388,11 @@ void QmlCompositeTypeManager::doComplete(QmlCompositeTypeResource *resource) void QmlCompositeTypeManager::checkComplete(QmlCompositeTypeData *unit) { - if (unit->status != QmlCompositeTypeData::Waiting) + if (unit->status != QmlCompositeTypeData::Waiting + && unit->status != QmlCompositeTypeData::WaitingResources) return; int waiting = 0; - for (int ii = 0; ii < unit->types.count(); ++ii) { - QmlCompositeTypeData *u = unit->types.at(ii).unit; - - if (!u) - continue; - - if (u->status == QmlCompositeTypeData::Error) { - unit->status = QmlCompositeTypeData::Error; - unit->errors = u->errors; - doComplete(unit); - return; - } else if (u->status == QmlCompositeTypeData::Waiting) { - waiting++; - } - } for (int ii = 0; ii < unit->resources.count(); ++ii) { QmlCompositeTypeResource *r = unit->resources.at(ii); @@ -429,28 +403,84 @@ void QmlCompositeTypeManager::checkComplete(QmlCompositeTypeData *unit) unit->status = QmlCompositeTypeData::Error; QmlError error; error.setUrl(unit->imports.baseUrl()); - error.setDescription(QLatin1String("Resource ") + r->url + - QLatin1String(" unavailable")); + error.setDescription(tr("Resource %1 unavailable").arg(r->url)); unit->errors << error; doComplete(unit); return; - } else if (r->status == QmlCompositeTypeData::Waiting) { + } else if (r->status == QmlCompositeTypeResource::Waiting) { waiting++; } } + if (waiting == 0) { + if (unit->status == QmlCompositeTypeData::WaitingResources) { + waiting += resolveTypes(unit); + if (unit->status != QmlCompositeTypeData::Error) { + if (waiting) + unit->status = QmlCompositeTypeData::Waiting; + } else { + return; + } + } else { + for (int ii = 0; ii < unit->types.count(); ++ii) { + QmlCompositeTypeData *u = unit->types.at(ii).unit; + + if (!u) + continue; + + if (u->status == QmlCompositeTypeData::Error) { + unit->status = QmlCompositeTypeData::Error; + unit->errors = u->errors; + doComplete(unit); + return; + } else if (u->status == QmlCompositeTypeData::Waiting) { + waiting++; + } + } + } + } + if (!waiting) { unit->status = QmlCompositeTypeData::Complete; doComplete(unit); } } -// ### Check ref counting in here -void QmlCompositeTypeManager::compile(QmlCompositeTypeData *unit) +int QmlCompositeTypeManager::resolveTypes(QmlCompositeTypeData *unit) { - QList<QmlScriptParser::TypeReference*> types = unit->data.referencedTypes(); + // not called until all resources are loaded (they include import URLs) int waiting = 0; + + foreach (QmlScriptParser::Import imp, unit->data.imports()) { + int dot = imp.version.indexOf(QLatin1Char('.')); + if (dot < 0) dot = imp.version.length(); + QString qmldir; + if (imp.type == QmlScriptParser::Import::File) { + QUrl importUrl = unit->imports.baseUrl().resolved(QUrl(imp.uri + QLatin1String("/qmldir"))); + for (int ii = 0; ii < unit->resources.count(); ++ii) { + if (unit->resources.at(ii)->url == importUrl) { + qmldir = QString::fromUtf8(unit->resources.at(ii)->data); + break; + } + } + } + if (!QmlEnginePrivate::get(engine)->addToImport( + &unit->imports, qmldir, imp.uri, imp.qualifier, imp.version.left(dot).toInt(), imp.version.mid(dot+1).toInt(), imp.type)) + { + QmlError error; + error.setUrl(unit->imports.baseUrl()); + error.setDescription(tr("Import %1 unavailable").arg(imp.uri)); + unit->status = QmlCompositeTypeData::Error; + unit->errorType = QmlCompositeTypeData::GeneralError; + unit->errors << error; + doComplete(unit); + return 0; + } + } + + QList<QmlScriptParser::TypeReference*> types = unit->data.referencedTypes(); + for (int ii = 0; ii < types.count(); ++ii) { QmlScriptParser::TypeReference *parserRef = types.at(ii); QByteArray typeName = parserRef->name.toUtf8(); @@ -478,7 +508,7 @@ void QmlCompositeTypeManager::compile(QmlCompositeTypeData *unit) unit->errorType = QmlCompositeTypeData::GeneralError; unit->errors << error; doComplete(unit); - return; + return 0; } if (ref.type) { @@ -521,12 +551,13 @@ void QmlCompositeTypeManager::compile(QmlCompositeTypeData *unit) if (urlUnit->errorType != QmlCompositeTypeData::AccessError) unit->errors << urlUnit->errors; doComplete(unit); - return; + return 0; case QmlCompositeTypeData::Complete: break; case QmlCompositeTypeData::Waiting: + case QmlCompositeTypeData::WaitingResources: unit->addref(); ref.unit->dependants << unit; waiting++; @@ -535,6 +566,13 @@ void QmlCompositeTypeManager::compile(QmlCompositeTypeData *unit) unit->types << ref; } + return waiting; +} + +// ### Check ref counting in here +void QmlCompositeTypeManager::compile(QmlCompositeTypeData *unit) +{ + int waiting = 0; QList<QUrl> resourceList = unit->data.referencedResources(); for (int ii = 0; ii < resourceList.count(); ++ii) { @@ -551,6 +589,9 @@ void QmlCompositeTypeManager::compile(QmlCompositeTypeData *unit) loadResource(resource); } + if (!url.toLocalFile().isEmpty() && url.path().endsWith("/qmldir") && resource->status==QmlCompositeTypeResource::Error) + continue; // ignore - can use filesystem dir instead + switch(resource->status) { case QmlCompositeTypeResource::Invalid: case QmlCompositeTypeResource::Error: @@ -558,8 +599,7 @@ void QmlCompositeTypeManager::compile(QmlCompositeTypeData *unit) { QmlError error; error.setUrl(unit->imports.baseUrl()); - error.setDescription(QLatin1String("Resource ") + resource->url + - QLatin1String(" unavailable")); + error.setDescription(tr("Resource %1 unavailable").arg(resource->url)); unit->errors << error; } doComplete(unit); @@ -579,11 +619,18 @@ void QmlCompositeTypeManager::compile(QmlCompositeTypeData *unit) unit->resources << resource; } - if (waiting) { - unit->status = QmlCompositeTypeData::Waiting; + if (waiting == 0) { + waiting += resolveTypes(unit); + if (unit->status != QmlCompositeTypeData::Error) { + if (!waiting) { + unit->status = QmlCompositeTypeData::Complete; + doComplete(unit); + } else { + unit->status = QmlCompositeTypeData::Waiting; + } + } } else { - unit->status = QmlCompositeTypeData::Complete; - doComplete(unit); + unit->status = QmlCompositeTypeData::WaitingResources; } } diff --git a/src/declarative/qml/qmlcompositetypemanager_p.h b/src/declarative/qml/qmlcompositetypemanager_p.h index 843a9cf..b6f84db 100644 --- a/src/declarative/qml/qmlcompositetypemanager_p.h +++ b/src/declarative/qml/qmlcompositetypemanager_p.h @@ -101,6 +101,7 @@ private: void doComplete(QmlCompositeTypeData *); void doComplete(QmlCompositeTypeResource *); void checkComplete(QmlCompositeTypeData *); + int resolveTypes(QmlCompositeTypeData *); QmlEngine *engine; typedef QHash<QString, QmlCompositeTypeData *> Components; diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 354114a..a3fb363 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -1027,6 +1027,7 @@ struct QmlEnginePrivate::ImportedNamespace { QList<int> minversions; QList<bool> isLibrary; QList<bool> isBuiltin; + QList<QString> qmlDirContent; bool find(const QByteArray& type, int *vmajor, int *vminor, QmlType** type_return, QUrl* url_return) const { @@ -1048,36 +1049,39 @@ struct QmlEnginePrivate::ImportedNamespace { } } else { QUrl url = QUrl(urls.at(i) + QLatin1String("/") + QString::fromUtf8(type) + QLatin1String(".qml")); - if (vmaj || vmin) { + QString qmldircontent = qmlDirContent.at(i); + if (vmaj || vmin || !qmldircontent.isEmpty()) { // Check version file - XXX cache these in QmlEngine! - QFile qmldir(toLocalFileOrQrc(QUrl(urls.at(i)+QLatin1String("/qmldir")))); - if (qmldir.open(QIODevice::ReadOnly)) { - do { - QByteArray lineba = qmldir.readLine(); - if (lineba.at(0) == '#') - continue; - int space1 = lineba.indexOf(' '); - if (qstrncmp(lineba,type,space1)==0) { - // eg. 1.2-5 - QString line = QString::fromUtf8(lineba); - space1 = line.indexOf(QLatin1Char(' ')); // refind in Unicode - int space2 = space1 >=0 ? line.indexOf(QLatin1Char(' '),space1+1) : -1; - QString mapversions = line.mid(space1+1,space2<0?line.length()-space1-2:space2-space1-1); - int dot = mapversions.indexOf(QLatin1Char('.')); - int dash = mapversions.indexOf(QLatin1Char('-')); - int mapvmaj = mapversions.left(dot).toInt(); - if (mapvmaj==vmaj) { - int mapvmin_from = (dash <= 0 ? mapversions.mid(dot+1) : mapversions.mid(dot+1,dash-dot-1)).toInt(); - int mapvmin_to = dash <= 0 ? mapvmin_from : mapversions.mid(dash+1).toInt(); - if (vmin >= mapvmin_from && vmin <= mapvmin_to) { - QStringRef mapfile = space2<0 ? QStringRef() : line.midRef(space2+1,line.length()-space2-2); - if (url_return) - *url_return = url.resolved(mapfile.toString()); - return true; - } + if (qmldircontent.isEmpty()) { + QFile qmldir(toLocalFileOrQrc(QUrl(urls.at(i)+QLatin1String("/qmldir")))); + if (qmldir.open(QIODevice::ReadOnly)) { + qmldircontent = QString::fromUtf8(qmldir.readAll()); + } + } + QString typespace = QString::fromUtf8(type)+QLatin1Char(' '); + QStringList lines = qmldircontent.split(QLatin1Char('\n')); + foreach (QString line, lines) { + if (line.isEmpty() || line.at(0) == QLatin1Char('#')) + continue; + if (line.startsWith(typespace)) { + // eg. 1.2-5 + int space1 = line.indexOf(QLatin1Char(' ')); + int space2 = space1 >=0 ? line.indexOf(QLatin1Char(' '),space1+1) : -1; + QString mapversions = line.mid(space1+1,space2<0?line.length()-space1-1:space2-space1-1); + int dot = mapversions.indexOf(QLatin1Char('.')); + int dash = mapversions.indexOf(QLatin1Char('-')); + int mapvmaj = mapversions.left(dot).toInt(); + if (mapvmaj==vmaj) { + int mapvmin_from = (dash <= 0 ? mapversions.mid(dot+1) : mapversions.mid(dot+1,dash-dot-1)).toInt(); + int mapvmin_to = dash <= 0 ? mapvmin_from : mapversions.mid(dash+1).toInt(); + if (vmin >= mapvmin_from && vmin <= mapvmin_to) { + QStringRef mapfile = space2<0 ? QStringRef() : line.midRef(space2+1,line.length()-space2-1); + if (url_return) + *url_return = url.resolved(mapfile.toString()); + return true; } } - } while (!qmldir.atEnd()); + } } } else { // XXX search non-files too! (eg. zip files, see QT-524) @@ -1106,7 +1110,7 @@ public: delete s; } - bool add(const QUrl& base, const QString& uri, const QString& prefix, int vmaj, int vmin, QmlScriptParser::Import::Type importType, const QStringList& importPath) + bool add(const QUrl& base, const QString& qmldircontent, const QString& uri, const QString& prefix, int vmaj, int vmin, QmlScriptParser::Import::Type importType, const QStringList& importPath) { QmlEnginePrivate::ImportedNamespace *s; if (prefix.isEmpty()) { @@ -1142,6 +1146,7 @@ public: s->minversions.prepend(vmin); s->isLibrary.prepend(importType == QmlScriptParser::Import::Library); s->isBuiltin.prepend(isbuiltin); + s->qmlDirContent.prepend(qmldircontent); return true; } @@ -1366,9 +1371,9 @@ QString QmlEngine::offlineStoragePath() const The base URL must already have been set with Import::setBaseUrl(). */ -bool QmlEnginePrivate::addToImport(Imports* imports, const QString& uri, const QString& prefix, int vmaj, int vmin, QmlScriptParser::Import::Type importType) const +bool QmlEnginePrivate::addToImport(Imports* imports, const QString& qmldircontent, const QString& uri, const QString& prefix, int vmaj, int vmin, QmlScriptParser::Import::Type importType) const { - bool ok = imports->d->add(imports->d->base,uri,prefix,vmaj,vmin,importType,fileImportPath); + bool ok = imports->d->add(imports->d->base,qmldircontent,uri,prefix,vmaj,vmin,importType,fileImportPath); if (qmlImportTrace()) qDebug() << "QmlEngine::addToImport(" << imports << uri << prefix << vmaj << "." << vmin << (importType==QmlScriptParser::Import::Library? "Library" : "File") << ": " << ok; return ok; diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index a74854d..bd1cab2 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -223,7 +223,7 @@ public: QmlImportsPrivate *d; }; - bool addToImport(Imports*, const QString& uri, const QString& prefix, int vmaj, int vmin, QmlScriptParser::Import::Type importType) const; + bool addToImport(Imports*, const QString& qmlDirContent,const QString& uri, const QString& prefix, int vmaj, int vmin, QmlScriptParser::Import::Type importType) const; bool resolveType(const Imports&, const QByteArray& type, QmlType** type_return, QUrl* url_return, int *version_major, int *version_minor, diff --git a/src/declarative/qml/qmlscriptparser.cpp b/src/declarative/qml/qmlscriptparser.cpp index fb84651..b61ffaa 100644 --- a/src/declarative/qml/qmlscriptparser.cpp +++ b/src/declarative/qml/qmlscriptparser.cpp @@ -424,6 +424,9 @@ bool ProcessAST::visit(AST::UiImport *node) if (node->fileName) { import.type = QmlScriptParser::Import::File; uri = node->fileName->asString(); + QUrl ref(uri); + ref.setPath(ref.path()+QLatin1String("/qmldir")); + _parser->_refUrls << ref; } else { import.type = QmlScriptParser::Import::Library; uri = asString(node->importUri); |